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.

Inspection of Objects:

The way to ask for the contents of an ObjC object is similar to the way to ask a struct in gdb. If the type of the object is declared in the Sourcecode, gdb can do this automatically.

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}

Message Name Mangling:

goes as follows:

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 _.

Operations on Messages:

You can set breakpoints in the same way as for C functions:

gdb> b _i_MyClass__done

You can call methods in one of two ways:

1) Calling using the mangled name:

You can use the mangled name to call a message. The first parameter to a message is the object, the receiver. The second argument is the selector. When you use the mangled names in gdb, you don't need the selector normally. However, the message to be called may explicitly reference it (not common). The rest of the arguments are the arguments for the message.

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.

2) Calling with message name as string using a compiled function

Insert the following function in your progran. Thanks to Kresten Krab Thorup.
#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);
}

Now you can do the message calls of the previous examples like this:

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.