diff --git a/gdb/NEWS b/gdb/NEWS index 5a0a76e..6d4ea20 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -133,6 +133,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/python.texi b/gdb/doc/python.texi index ba0a7fd..33680fb 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. @@ -2175,6 +2178,265 @@ 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}. + +A 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 + +A 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.invoke(self, obj, args) +This is the method which does the @emph{work} of the xmethod. +@var{obj} is the object on which the method is being invoked, and +@var{args} is the tuple of arguments to the method. @var{obj} and the +elements of @var{args} are @code{gdb.Value} objects. +@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 a Xmethod +@subsubsection Writing a 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 +xmethod matcher can be defined as follows: + +@smallexample +class MyClassMatcher(gdb.xmethod.XMethodMatcher): + def __init__(self): + gdb.xmethod.XMethodMatcher.__init__(self, 'MyMatcher') + # List of methods 'managed' by this matcher + self.methods = [gdb.xmethod.XMethod('geta'), + gdb.xmethod.XMethod('sum')] + + def match(self, class_type, method_name): + if class_type.tag != 'MyClass': + return None + if method_name == 'geta' and self.methods[0].enabled: + return MyClassWorker_geta() + elif method_name == 'operator+' and self.methods[1].enabled: + return MyClassWorker_plus() + else: + return None +@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. Also, a worker object is returned only if the +corresponding entry in the @code{methods} attribute is enabled. + +The implementation of the worker classes returned by the matcher above +is as follows: + +@smallexample +class MyClassWorker_geta(gdb.xmethod.XMethodWorker): + def get_arg_types(self): + return None + + def invoke(self, obj, args): + return obj['a_'] + + +class MyClassWorker_plus(gdb.xmethod.XMethodWorker): + def get_arg_types(self): + return gdb.lookup_type('MyClass') + + def invoke(self, obj, args): + return obj['a_'] + args[0]['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 + @node Inferiors In Python @subsubsection Inferiors In Python @cindex inferiors in Python