diff options
author | Siva Chandra <sivachandra@chromium.org> | 2014-03-30 16:24:50 -0700 |
---|---|---|
committer | Siva Chandra <sivachandra@chromium.org> | 2014-06-03 10:07:45 -0700 |
commit | 0c6e92a52c60347a3e5689150d25b1cb87eeb258 (patch) | |
tree | 1e28d3e0c76de1534e50f117c51b755df753a798 | |
parent | 883964a75e8c6531f167391354f1a4d83d203988 (diff) | |
download | gdb-0c6e92a52c60347a3e5689150d25b1cb87eeb258.zip gdb-0c6e92a52c60347a3e5689150d25b1cb87eeb258.tar.gz gdb-0c6e92a52c60347a3e5689150d25b1cb87eeb258.tar.bz2 |
Documentation of the xmethod support in GDB Python API.
* NEWS (Python Scripting): Add entry about the new xmethods
feature.
doc/
* python.texi (Xmethods In Python, XMethod API)
(Writing an Xmethod): New nodes.
(Python API): New menu entries "Xmethods In Python",
"Xmethod API", "Writing an Xmethod".
-rw-r--r-- | gdb/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/NEWS | 5 | ||||
-rw-r--r-- | gdb/doc/ChangeLog | 7 | ||||
-rw-r--r-- | gdb/doc/python.texi | 345 |
4 files changed, 362 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index b66a9f8..93a89a9 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,10 @@ 2014-06-03 Siva Chandra Reddy <sivachandra@google.com> + * NEWS (Python Scripting): Add entry about the new xmethods + feature. + +2014-06-03 Siva Chandra Reddy <sivachandra@google.com> + * python/py-xmethods.c: New file. * python/py-objfile.c (objfile_object): New field 'xmethods'. (objfpy_dealloc): XDECREF on the new xmethods field. @@ -153,6 +153,11 @@ qXfer:btrace:read's annex ** Valid Python operations on gdb.Value objects representing structs/classes invoke the corresponding overloaded operators if available. + ** New `Xmethods' feature in the Python API. Xmethods are + additional methods or replacements for existing methods of a C++ + class. This feature is useful for those cases where a method + defined in C++ source code could be inlined or optimized out by + the compiler, making it unavailable to GDB. * New targets PowerPC64 GNU/Linux little-endian powerpc64le-*-linux* diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index ca1d4fe..16a60f3 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,10 @@ +2014-06-03 Siva Chandra Reddy <sivachandra@google.com> + + * python.texi (Xmethods In Python, XMethod API) + (Writing an Xmethod): New nodes. + (Python API): New menu entries "Xmethods In Python", + "Xmethod API", "Writing an Xmethod". + 2014-06-02 Doug Evans <xdje42@gmail.com> * guile.texi (Guile API): Add entry for Parameters In Guile. diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index 006b873..1ba248b 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -144,6 +144,9 @@ optional arguments while skipping others. Example: * Frame Filter API:: Filtering Frames. * Frame Decorator API:: Decorating Frames. * Writing a Frame Filter:: Writing a Frame Filter. +* Xmethods In Python:: Adding and replacing methods of C++ classes. +* Xmethod API:: Xmethod types. +* Writing an Xmethod:: Writing an xmethod. * Inferiors In Python:: Python representation of inferiors (processes) * Events In Python:: Listening for events from @value{GDBN}. * Threads In Python:: Accessing inferior threads from Python. @@ -2174,6 +2177,348 @@ printed hierarchically. Another approach would be to combine the marker in the inlined frame, and also show the hierarchical relationship. +@node Xmethods In Python +@subsubsection Xmethods In Python +@cindex xmethods in Python + +@dfn{Xmethods} are additional methods or replacements for existing +methods of a C@t{++} class. This feature is useful for those cases +where a method defined in C@t{++} source code could be inlined or +optimized out by the compiler, making it unavailable to @value{GDBN}. +For such cases, one can define an xmethod to serve as a replacement +for the method defined in the C@t{++} source code. @value{GDBN} will +then invoke the xmethod, instead of the C@t{++} method, to +evaluate expressions. One can also use xmethods when debugging +with core files. Moreover, when debugging live programs, invoking an +xmethod need not involve running the inferior (which can potentially +perturb its state). Hence, even if the C@t{++} method is available, it +is better to use its replacement xmethod if one is defined. + +The xmethods feature in Python is available via the concepts of an +@dfn{xmethod matcher} and an @dfn{xmethod worker}. To +implement an xmethod, one has to implement a matcher and a +corresponding worker for it (more than one worker can be +implemented, each catering to a different overloaded instance of the +method). Internally, @value{GDBN} invokes the @code{match} method of a +matcher to match the class type and method name. On a match, the +@code{match} method returns a list of matching @emph{worker} objects. +Each worker object typically corresponds to an overloaded instance of +the xmethod. They implement a @code{get_arg_types} method which +returns a sequence of types corresponding to the arguments the xmethod +requires. @value{GDBN} uses this sequence of types to perform +overload resolution and picks a winning xmethod worker. A winner +is also selected from among the methods @value{GDBN} finds in the +C@t{++} source code. Next, the winning xmethod worker and the +winning C@t{++} method are compared to select an overall winner. In +case of a tie between a xmethod worker and a C@t{++} method, the +xmethod worker is selected as the winner. That is, if a winning +xmethod worker is found to be equivalent to the winning C@t{++} +method, then the xmethod worker is treated as a replacement for +the C@t{++} method. @value{GDBN} uses the overall winner to invoke the +method. If the winning xmethod worker is the overall winner, then +the corresponding xmethod is invoked via the @code{invoke} method +of the worker object. + +If one wants to implement an xmethod as a replacement for an +existing C@t{++} method, then they have to implement an equivalent +xmethod which has exactly the same name and takes arguments of +exactly the same type as the C@t{++} method. If the user wants to +invoke the C@t{++} method even though a replacement xmethod is +available for that method, then they can disable the xmethod. + +@xref{Xmethod API}, for API to implement xmethods in Python. +@xref{Writing an Xmethod}, for implementing xmethods in Python. + +@node Xmethod API +@subsubsection Xmethod API +@cindex xmethod API + +The @value{GDBN} Python API provides classes, interfaces and functions +to implement, register and manipulate xmethods. +@xref{Xmethods In Python}. + +An xmethod matcher should be an instance of a class derived from +@code{XMethodMatcher} defined in the module @code{gdb.xmethod}, or an +object with similar interface and attributes. An instance of +@code{XMethodMatcher} has the following attributes: + +@defvar name +The name of the matcher. +@end defvar + +@defvar enabled +A boolean value indicating whether the matcher is enabled or disabled. +@end defvar + +@defvar methods +A list of named methods managed by the matcher. Each object in the list +is an instance of the class @code{XMethod} defined in the module +@code{gdb.xmethod}, or any object with the following attributes: + +@table @code + +@item name +Name of the xmethod which should be unique for each xmethod +managed by the matcher. + +@item enabled +A boolean value indicating whether the xmethod is enabled or +disabled. + +@end table + +The class @code{XMethod} is a convenience class with same +attributes as above along with the following constructor: + +@defun XMethod.__init__(self, name) +Constructs an enabled xmethod with name @var{name}. +@end defun +@end defvar + +@noindent +The @code{XMethodMatcher} class has the following methods: + +@defun XMethodMatcher.__init__(self, name) +Constructs an enabled xmethod matcher with name @var{name}. The +@code{methods} attribute is initialized to @code{None}. +@end defun + +@defun XMethodMatcher.match(self, class_type, method_name) +Derived classes should override this method. It should return a +xmethod worker object (or a sequence of xmethod worker +objects) matching the @var{class_type} and @var{method_name}. +@var{class_type} is a @code{gdb.Type} object, and @var{method_name} +is a string value. If the matcher manages named methods as listed in +its @code{methods} attribute, then only those worker objects whose +corresponding entries in the @code{methods} list are enabled should be +returned. +@end defun + +An xmethod worker should be an instance of a class derived from +@code{XMethodWorker} defined in the module @code{gdb.xmethod}, +or support the following interface: + +@defun XMethodWorker.get_arg_types(self) +This method returns a sequence of @code{gdb.Type} objects corresponding +to the arguments that the xmethod takes. It can return an empty +sequence or @code{None} if the xmethod does not take any arguments. +If the xmethod takes a single argument, then a single +@code{gdb.Type} object corresponding to it can be returned. +@end defun + +@defun XMethodWorker.__call__(self, *args) +This is the method which does the @emph{work} of the xmethod. The +@var{args} arguments is the tuple of arguments to the xmethod. Each +element in this tuple is a gdb.Value object. The first element is +always the @code{this} pointer value. +@end defun + +For @value{GDBN} to lookup xmethods, the xmethod matchers +should be registered using the following function defined in the module +@code{gdb.xmethod}: + +@defun register_xmethod_matcher(locus, matcher, replace=False) +The @code{matcher} is registered with @code{locus}, replacing an +existing matcher with the same name as @code{matcher} if +@code{replace} is @code{True}. @code{locus} can be a +@code{gdb.Objfile} object (@pxref{Objfiles In Python}), or a +@code{gdb.Progspace} object (@pxref{Program Spaces In Python}), or +@code{None}. If it is @code{None}, then @code{matcher} is registered +globally. +@end defun + +@node Writing an Xmethod +@subsubsection Writing an Xmethod +@cindex writing xmethods in Python + +Implementing xmethods in Python will require implementing xmethod +matchers and xmethod workers (@pxref{Xmethods In Python}). Consider +the following C@t{++} class: + +@smallexample +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; +@} +@end smallexample + +@noindent +Let us define two xmethods for the class @code{MyClass}, one +replacing the method @code{geta}, and another adding an overloaded +flavor of @code{operator+} which takes a @code{MyClass} argument (the +C@t{++} code above already has an overloaded @code{operator+} +which takes an @code{int} argument). The xmethod matcher can be +defined as follows: + +@smallexample +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 +@end smallexample + +@noindent +Notice that the @code{match} method of @code{MyClassMatcher} returns +a worker object of type @code{MyClassWorker_geta} for the @code{geta} +method, and a worker object of type @code{MyClassWorker_plus} for the +@code{operator+} method. This is done indirectly via helper classes +derived from @code{gdb.xmethod.XMethod}. One does not need to use the +@code{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 @code{methods} attribute of the matcher. This will then +facilitate enabling and disabling individual xmethods via the +@code{enable/disable} commands. Notice also that a worker object is +returned only if the corresponding entry in the @code{methods} attribute +of the matcher is enabled. + +The implementation of the worker classes returned by the matcher setup +above is as follows: + +@smallexample +class MyClassWorker_geta(gdb.xmethod.XMethodWorker): + def get_arg_types(self): + return None + + def __call__(self, obj): + return obj['a_'] + + +class MyClassWorker_plus(gdb.xmethod.XMethodWorker): + def get_arg_types(self): + return gdb.lookup_type('MyClass') + + def __call__(self, obj, other): + return obj['a_'] + other['a_'] +@end smallexample + +For @value{GDBN} to actually lookup a xmethod, it has to be +registered with it. The matcher defined above is registered with +@value{GDBN} globally as follows: + +@smallexample +gdb.xmethod.register_xmethod_matcher(None, MyClassMatcher()) +@end smallexample + +If an object @code{obj} of type @code{MyClass} is initialized in C@t{++} +code as follows: + +@smallexample +MyClass obj(5); +@end smallexample + +@noindent +then, after loading the Python script defining the xmethod matchers +and workers into @code{GDBN}, invoking the method @code{geta} or using +the operator @code{+} on @code{obj} will invoke the xmethods +defined above: + +@smallexample +(gdb) p obj.geta() +$1 = 5 + +(gdb) p obj + obj +$2 = 10 +@end smallexample + +Consider another example with a C++ template class: + +@smallexample +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_; +@}; +@end smallexample + +Let us implement an xmethod for the above class which serves as a +replacement for the @code{footprint} method. The full code listing +of the xmethod workers and xmethod matchers is as follows: + +@smallexample +class MyTemplateWorker_footprint(gdb.xmethod.XMethodWorker): + def __init__(self, class_type): + self.class_type = class_type + + def get_arg_types(self): + return None + + 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) +@end smallexample + +Notice that, in this example, we have not used the @code{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. + @node Inferiors In Python @subsubsection Inferiors In Python @cindex inferiors in Python |