# Accessor methods for libstdc++. # Copyright (C) 2022 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import gdb import re try: from typing import Optional except ImportError: pass class AccessorBase(object): """Base class for accessors of C++ STL types.""" _name = None # type: str _typere = None # type: str _typerx = None # type: Optional[re.Match] _ptr = None # type: Optional[gdb.Value] @classmethod def is_type(cls, otype): # type: (gdb.Type) -> None """Return true if the provided type is of this class.""" if cls._typerx is None: cls._typerx = re.compile(cls._typere) return cls._typerx.match(otype.tag) is not None def __init__(self, ptr): # type: (gdb.Value) -> None if not self.is_type(ptr.type): raise ValueError("Value has type '%s', expected '%s'" % (str(ptr.type), self._name)) self._ptr = ptr def __str__(self): # type: () -> str return str(self._ptr) class SmartPtr(AccessorBase): """Base accessor for C++ STL smart pointers.""" def get(self): # type: () -> Optional[gdb.Value] """Return the pointer owned by this smart pointer, or None.""" raise NotImplementedError("get() not implemented") class UniquePtr(SmartPtr): """Accessor for std::unique_ptr<>.""" _name = 'std::unique_ptr' _typere = r'^std::(?:__\d+::)?unique_ptr<.*>$' _newre = None # type: Optional[re.Match] _oldre = None # type: Optional[re.Match] def get(self): # type: () -> Optional[gdb.Value] """Return the pointer owned by std::unique_ptr<>, or None.""" if self._ptr is None: return None impl_type = self._ptr.type.fields()[0].type.strip_typedefs() # Check for new implementations first: if UniquePtr._newre is None: UniquePtr._newre = re.compile(r'^std::(?:__\d+::)?__uniq_ptr_(data|impl)<.*>$') if UniquePtr._newre.match(impl_type): tuple_member = self._ptr['_M_t']['_M_t'] else: if UniquePtr._oldre is None: UniquePtr._oldre = re.compile(r'^std::(?:__\d+::)?tuple<.*>$') if UniquePtr._oldre.match(impl_type): tuple_member = self._ptr['_M_t'] else: raise ValueError("Unsupported implementation for unique_ptr: %s" % str(impl_type)) tuple_impl_type = tuple_member.type.fields()[0].type # _Tuple_impl tuple_head_type = tuple_impl_type.fields()[1].type # _Head_base head_field = tuple_head_type.fields()[0] if head_field.name == '_M_head_impl': return tuple_member['_M_head_impl'] if head_field.is_base_class: return tuple_member.cast(head_field.type) return None class SharedPtr(SmartPtr): """Accessor for std::shared_ptr<>.""" _name = 'std::{shared,weak}_ptr' _typere = r'^std::(?:__\d+::)?(?:shared|weak)_ptr<.*>$' def get(self): # type: () -> Optional[gdb.Value] """Return the pointer managed by std::shared_ptr<>, or None.""" if self._ptr is None: return None return self._ptr['_M_ptr'] def _get_refcounts(self): # type: () -> Optional[gdb.Value] """Return the refcount struct or None.""" return self._ptr['_M_refcount']['_M_pi'] if self._ptr else None def use_count(self): # type: () -> int """Return the use count of the std::shared_ptr<>.""" refcounts = self._get_refcounts() return refcounts['_M_use_count'] if refcounts else 0 def weak_count(self): # type: () -> int """Return the weak count of the std::shared_ptr<>.""" refcounts = self._get_refcounts() return refcounts['_M_weak_count'] if refcounts else 0