This file should enable the reader to examine running ObjC-Programs using GNU Objective-C and gdb on non-NeXT-Machines. The examples are tested with gcc-2.6.3 and gdb-4.13.
Suggestions are welcome.
ObjC-source> Class1 anObject;
can be inspected by:
gdb> p *anObject;
However, if the type is not declared or the object stored in the variable is not anymore of the declared type, you have to find out the class of the Object and then tell gdb to inspect the object like you would to inspect a structure.
ObjC-source> id foo2; // has a single instance var called a
you get the Class of this Object like this (gdb's answer inserted):
gdb> call _i_Object__name(foo2,"")
answer> $31 = (unsigned char *) 0x10000b1c "Foo0"
You know then the Class is Foo0 and can use the class name to inspect foo2:
gdb> p (struct Foo0)*foo2
answer> $32 = {isa = 0x10000244, a = 0, aid = 0x10005590}
The method of MyClass named -do:with: looks like this in gdb:
_i_MyClass__do_with_
The method of MyClass named -done looks like this in gdb: _i_MyClass__done
Factory methods have a _c_ at the beginning instead of _i_ The method of MyClass named +version looks like this in gdb: _c_MyClass__version.
To be exact: Every method starts with either _i_ or _c_. The name of the Class follows. Them come two _, for Methods that are not part of Categories. The __ turns to _categoryName_ then. The parts of the method name are appended, substituting each : with a _.
gdb> b _i_MyClass__done
An example. Here are some message calls in ObjC:
ObjC-Source 1> id foo1;
ObjC-Source 2>
ObjC-Source 3> [foo1 do: "Text" with: 4];
ObjC-Source 4> [foo1 eat: "Hamburger"];
ObjC-Source 5> [foo1 done];
First you must find out what the class of foo1 is and construct the mangled name as show above. Assuming the Class is Class1:
_i_Class1__do_with_
_i_Class1__eat
_i_Class1__done
The calls in the code example may be done like this in gdb , assuming that Object foo1 already exists (that means, execution of the program already passed line 1).
gdb> call _i_Class1__do_with_(foo1,"","Text",4)
gdb> call _i_Class1__eat_(foo1,"","Hamburger")
gdb> call _i_Class1__done(foo1,"")
Note that I inserted a dummy string for the selector, assuming that the messages doesn't explicitly access it. A selector is not a string, but since this call doesn't provide the correct selector anyway, I inserted the pointer that is most easily created in gdb, an empty string.
#include#include int method_get_sizeof_arguments (Method*); // Missing in objc/*.h volatile retval_t ocs(id object, char *opname, ...) { SEL op = sel_get_uid (opname); Method* m = class_get_instance_method(object->class_pointer, op); IMP imp; arglist_t args; retval_t result; if (!m) { fprintf(stderr,"Error in message call\n"); return ((void *)0); } imp = objc_msg_lookup (object, op); args = __builtin_apply_args(); result = __builtin_apply((apply_t)imp, args, method_get_sizeof_arguments (m)); __builtin_return (result); }
gdb> call ocs(foo1,"do:with:","Text",4)
gdb> call ocs(foo1,"eat:","Hamburger")
gdb> call ocs(foo1,"done")
Please note that error handling is rare. You'll see the error message when you type in a message that is not understood by the object.
Both solutions (mangled message names or string-converting function) will break the program with a segmentation fault when you pass something that is not an ObjC-Object as first parameter.
The first solution has the disadvantage that you must know the exact class of the object (and the category the message is defined in, if any) to determine the mangled name of the right message. The second solution does this automatically for you, but has the disadvantage that return values are interpreted as pointers in any case. For example, if the message returns the integer value 5, gdb will answer:
$3 = (void *) 0x5
non-32-bit data types like double will become unreadable then.
A better solution to prevent the type of the return value if it is a low-level type would be a simple text substitution to determine the right mangled name automatically in gdb
[leaving out the :of message name and categories]
gdb> objc-call foo2 do "Text" with 4
could be translated to (using UNIX shell syntax. Please note that some HTML readers like Mosaic show the Backquote like a normal quote.):
gdb> call _i_call _i_Object__name($1)`__$2_$4_($1,"dummy",$3,$5)
Maybe this is easy to do with tcl/expect. There's no solution for this yet and I think it is more likely that gdb will be extended to understand [foo2 do: "Text" with: 4] directly.
The different return type handling of the two calling conventions doesnt matter if the return value is an ObjC object. You'll get a pointer to it and then can operate on this pointer, ask for the class etc.
gdb> call ocs(foo2,"getaid")
answer> $9 =(void *) 0x100055b0 or gdb> call _i_Foo0__getaid(foo2,"")
answer> $10 = (struct objc_object *) 0x100055b0
return pointers to an Object. You can then do:
gdb> call _i_Object__name((void *) 0x100055b0)
answer> $2 = (unsigned char *) 0x10000b34 "Inti"
gdb> p (struct Inti)*0x10000b34
answer> $3 = {isa = 0x496e7469, a = 0}
Thanks to Pieter Schoenmakers for some clarifications.