Implementing xmethods in Python will require implementing xmethod matchers and xmethod workers (see Xmethods In Python). Consider the following C++ class:
class MyClass { public: MyClass (int a) : a_(a) { } int geta (void) { return a_; } int operator+ (int b); private: int a_; }; int MyClass::operator+ (int b) { return a_ + b; }
Let us define two xmethods for the class MyClass
, one
replacing the method geta
, and another adding an overloaded
flavor of operator+
which takes a MyClass
argument (the
C++ code above already has an overloaded operator+
which takes an int
argument). The xmethod matcher can be
defined as follows:
class MyClass_geta(gdb.xmethod.XMethod): def __init__(self): gdb.xmethod.XMethod.__init__(self, 'geta') def get_worker(self, method_name): if method_name == 'geta': return MyClassWorker_geta() class MyClass_sum(gdb.xmethod.XMethod): def __init__(self): gdb.xmethod.XMethod.__init__(self, 'sum') def get_worker(self, method_name): if method_name == 'operator+': return MyClassWorker_plus() class MyClassMatcher(gdb.xmethod.XMethodMatcher): def __init__(self): gdb.xmethod.XMethodMatcher.__init__(self, 'MyClassMatcher') # List of methods 'managed' by this matcher self.methods = [MyClass_geta(), MyClass_sum()] def match(self, class_type, method_name): if class_type.tag != 'MyClass': return None workers = [] for method in self.methods: if method.enabled: worker = method.get_worker(method_name) if worker: workers.append(worker) return workers
Notice that the match
method of MyClassMatcher
returns
a worker object of type MyClassWorker_geta
for the geta
method, and a worker object of type MyClassWorker_plus
for the
operator+
method. This is done indirectly via helper classes
derived from gdb.xmethod.XMethod
. One does not need to use the
methods
attribute in a matcher as it is optional. However, if a
matcher manages more than one xmethod, it is a good practice to list the
xmethods in the methods
attribute of the matcher. This will then
facilitate enabling and disabling individual xmethods via the
enable/disable
commands. Notice also that a worker object is
returned only if the corresponding entry in the methods
attribute
of the matcher is enabled.
The implementation of the worker classes returned by the matcher setup above is as follows:
class MyClassWorker_geta(gdb.xmethod.XMethodWorker): def get_arg_types(self): return None def get_result_type(self, obj): return gdb.lookup_type('int') def __call__(self, obj): return obj['a_'] class MyClassWorker_plus(gdb.xmethod.XMethodWorker): def get_arg_types(self): return gdb.lookup_type('MyClass') def get_result_type(self, obj): return gdb.lookup_type('int') def __call__(self, obj, other): return obj['a_'] + other['a_']
For gdb to actually lookup a xmethod, it has to be registered with it. The matcher defined above is registered with gdb globally as follows:
gdb.xmethod.register_xmethod_matcher(None, MyClassMatcher())
If an object obj
of type MyClass
is initialized in C++
code as follows:
MyClass obj(5);
then, after loading the Python script defining the xmethod matchers
and workers into GDBN
, invoking the method geta
or using
the operator +
on obj
will invoke the xmethods
defined above:
(gdb) p obj.geta() $1 = 5 (gdb) p obj + obj $2 = 10
Consider another example with a C++ template class:
template <class T> class MyTemplate { public: MyTemplate () : dsize_(10), data_ (new T [10]) { } ~MyTemplate () { delete [] data_; } int footprint (void) { return sizeof (T) * dsize_ + sizeof (MyTemplate<T>); } private: int dsize_; T *data_; };
Let us implement an xmethod for the above class which serves as a
replacement for the footprint
method. The full code listing
of the xmethod workers and xmethod matchers is as follows:
class MyTemplateWorker_footprint(gdb.xmethod.XMethodWorker): def __init__(self, class_type): self.class_type = class_type def get_arg_types(self): return None def get_result_type(self): return gdb.lookup_type('int') def __call__(self, obj): return (self.class_type.sizeof + obj['dsize_'] * self.class_type.template_argument(0).sizeof) class MyTemplateMatcher_footprint(gdb.xmethod.XMethodMatcher): def __init__(self): gdb.xmethod.XMethodMatcher.__init__(self, 'MyTemplateMatcher') def match(self, class_type, method_name): if (re.match('MyTemplate<[ \t\n]*[_a-zA-Z][ _a-zA-Z0-9]*>', class_type.tag) and method_name == 'footprint'): return MyTemplateWorker_footprint(class_type)
Notice that, in this example, we have not used the methods
attribute of the matcher as the matcher manages only one xmethod. The
user can enable/disable this xmethod by enabling/disabling the matcher
itself.