Mirror of the gdb mailing list
 help / color / mirror / Atom feed
* [help] Calling malloc() from a Python pretty-printer
@ 2014-09-23  8:15 Marc Mezzarobba
  2014-09-25  9:35 ` Phil Muldoon
  0 siblings, 1 reply; 3+ messages in thread
From: Marc Mezzarobba @ 2014-09-23  8:15 UTC (permalink / raw)
  To: gdb

Dear gdb gurus,

(This is a repost of a question that I sent to the gdb@gnu mailing list 
a few days ago. My apologies to people who read both lists!)

Is it supposed to be okay to call an inferior's function, and 
specifically malloc(), from a Python pretty-printer?

My understanding of the documentation was that it should work. But when 
my pretty-printer that calls malloc() is invoked while the selected 
stack frame is not the innermost one, gdb complains that it detected an 
internal problem or just crashes. What am I doing wrong? Is there a fine 
print I missed? Or is that a bug?

Here is a complete example:


==> foo.c <==
struct foo { int val; };

int bar(struct foo x) {
    struct foo y = x;
    --y.val;
    if (!y.val) return 0;
    return bar(y);
}

int main(void) {
    struct foo x = { .val = 42 };
    return bar(x);
}

==> foo-gdb.py <==
class Printer(object):
    def __init__(self):
        pass
    def to_string(self):
        gdb.lookup_symbol("malloc")[0].value()(256)
        return "tada"

def lookup_type(val):
    return Printer()

gdb.printing.register_pretty_printer(gdb, lookup_type)

==> transcript <==
~/docs/vrac/pygdb$ gdb foo
GNU gdb (Debian 7.7.1+dfsg-3) 7.7.1
[...]
Reading symbols from foo...done.
(gdb) break bar
Breakpoint 1 at 0x4004c1: file foo.c, line 4.
(gdb) r
Starting program: /home/marc/docs/vrac/pygdb/foo 

Breakpoint 1, bar (x=tada) at foo.c:4
4           struct foo y = x;
(gdb) c 10
Will ignore next 9 crossings of breakpoint 1.  Continuing.

Breakpoint 1, bar (x=tada) at foo.c:4
4           struct foo y = x;
(gdb) up
#1  0x00000000004004e8 in bar (x=tada) at foo.c:7
7           return bar(y);
/home/zumbi/gdb-7.7.1+dfsg/gdb/frame.c:2139: internal-error: 
get_frame_pc_if_available: Assertion `frame->next != NULL' failed.             
A problem internal to GDB has been detected,                          
further debugging may prove unreliable.                               
Quit this debugging session? (y or n) y

/home/zumbi/gdb-7.7.1+dfsg/gdb/frame.c:2139: internal-error: 
get_frame_pc_if_available: Assertion `frame->next != NULL' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.


(In case someone has a better approach to suggest, here is what I am 
trying to achieve. I am working with a library that provides a version 
of sprintf() for its custom data structures, and I would like to write a 
lightweight pretty-printer that reuses this sprintf(). Given my use 
cases, I don't think it is much of a problem if the pretty-printer needs 
to be disabled to debug some issues where the additional allocations are 
likely to interact with the actual problem. And if possible I would like 
to avoid writing a separate Python interface for the library...)

Can someone help me?


Thanks a lot,

-- 
Marc Mezzarobba


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [help] Calling malloc() from a Python pretty-printer
  2014-09-23  8:15 [help] Calling malloc() from a Python pretty-printer Marc Mezzarobba
@ 2014-09-25  9:35 ` Phil Muldoon
  2014-09-25 12:04   ` Marc Mezzarobba
  0 siblings, 1 reply; 3+ messages in thread
From: Phil Muldoon @ 2014-09-25  9:35 UTC (permalink / raw)
  To: Marc Mezzarobba, gdb

On 23/09/14 09:10, Marc Mezzarobba wrote:
> Dear gdb gurus,
>
> (This is a repost of a question that I sent to the gdb@gnu mailing list
> a few days ago. My apologies to people who read both lists!)
>
> Is it supposed to be okay to call an inferior's function, and
> specifically malloc(), from a Python pretty-printer?

Though not expressly forbidden it is highly discouraged to call (in
GDB parlance, an "inferior function call") in a pretty-printer.  The
results are too unpredictable.  The inferior call might generate a
signal (which in GDB will cause an error and the inferior will be
stopped at the signal emission phase), or hit a breakpoint (similar I
think to the signal), or a whole host of things where the pretty
printer looses control of the inferior.  An inferior function call
generates a temporary "dummy" frame to execute the call, and there are
several specialized conditions and limitations to be aware of (some of
which I detailed earlier.)


> My understanding of the documentation was that it should work.

It should, but see above.

> But when 
> my pretty-printer that calls malloc() is invoked while the selected
> stack frame is not the innermost one, gdb complains that it detected an
> internal problem or just crashes. What am I doing wrong? Is there a fine
> print I missed? Or is that a bug?

That is a bug.  Your call stack is smashed now, and GDB is saying it
cannot find the next frame.  This should never happen. I would be
curious to see what the result of:

(gdb) call malloc (1024)

are from your inferior, or in your pretty-printer the equivalent:

foo = gdb.parse_and_eval (malloc (1024))

Also a backtrace from the crashing GDB would be optimal if you can
generate one.

> (In case someone has a better approach to suggest, here is what I am
> trying to achieve. I am working with a library that provides a version
> of sprintf() for its custom data structures, and I would like to write a
> lightweight pretty-printer that reuses this sprintf(). Given my use
> cases, I don't think it is much of a problem if the pretty-printer needs
> to be disabled to debug some issues where the additional allocations are
> likely to interact with the actual problem. And if possible I would like
> to avoid writing a separate Python interface for the library...)

I am curious why you need to call malloc? Generally if you need to
store information about an inferior during pretty-printing, it is
often preferable to just allocate that storage in python.  So say you
needed to store an array of integers during you call, instead of doing
something like:

foo = gdb.parse_and_eval (calloc (100, sizeof(int)))

Just instead create a python list in the pretty printer:

foo = []

Then add to the list in Python.  You can make such lists last the
duration of the pretty printing call, or global.  Usual Python syntax
applies.

Cheers,

Phil



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [help] Calling malloc() from a Python pretty-printer
  2014-09-25  9:35 ` Phil Muldoon
@ 2014-09-25 12:04   ` Marc Mezzarobba
  0 siblings, 0 replies; 3+ messages in thread
From: Marc Mezzarobba @ 2014-09-25 12:04 UTC (permalink / raw)
  To: gdb

Phil Muldoon wrote:
> That is a bug.  Your call stack is smashed now, and GDB is saying it
> cannot find the next frame.  This should never happen. I would be
> curious to see what the result of:
> 
> (gdb) call malloc (1024)
> 
> are from your inferior,

Thank you very much for your reply.

Here is what I get in various situations (after removing the call to
malloc from the pretty-printer):

(gdb) r
Starting program: /home/marc/docs/vrac/pygdb/foo 

Breakpoint 1, bar (x=tada) at foo.c:4
4           struct foo y = x;
(gdb) call malloc (1024)
$1 = (void *) 0x601010
(gdb) c 10
Will ignore next 9 crossings of breakpoint 1.  Continuing.

Breakpoint 1, bar (x=tada) at foo.c:4
4           struct foo y = x;
(gdb) call malloc (1024)
$2 = (void *) 0x601420
(gdb) up
#1  0x00000000004004e8 in bar (x=tada) at foo.c:7
7           return bar(y);
(gdb) call malloc (1024)
$3 = (void *) 0x601830

> or in your pretty-printer the equivalent:
> 
> foo = gdb.parse_and_eval (malloc (1024))

The return values of malloc() are exactly the same as above, but (like
in my original example) gdb fails after printing

#1  0x00000000004004e8 in bar (x=tada) at foo.c:7
7           return bar(y);

> Also a backtrace from the crashing GDB would be optimal if you can
> generate one.

Here is what I managed to get. Note that this is not with foo.c but
with a significantly more complicated inferior (involving a dlopened
object that calls the Maple C API, with both Maple and the master
program using an LD_PRELOADed libgmp...). Also, crashes apparently
tend to occur when the inferior was itself executing memory
management functions when it was interrupted. I'm also including a
partial backtrace of the inferior in case this is relevant.

GDB:

#0  frame_unwind_pc (this_frame=0x170002)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/frame.c:761
#1  0x000000000065d48c in get_frame_address_in_block (
    this_frame=this_frame@entry=0x2409e00)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/frame.c:2162
#2  0x000000000065d592 in get_frame_address_in_block_if_available (
    this_frame=this_frame@entry=0x2409e00, pc=pc@entry=0x7fff3f753040)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/frame.c:2226
#3  0x000000000051b514 in get_frame_block (frame=0x2409e00, 
    addr_in_block=addr_in_block@entry=0x0)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/blockframe.c:62
#4  0x0000000000607e6d in dwarf_expr_frame_base (baton=0x7fff3f7531c0, 
    start=0x7fff3f7530f8, length=0x7fff3f753100)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/dwarf2loc.c:360
#5  0x00000000006027b9 in execute_stack_op (ctx=ctx@entry=0x1748db0, 
    op_ptr=0x7fd7f749db02 "\"h", op_ptr@entry=0x7fd7f749daff "\221\340|\"h", 
    op_end=op_end@entry=0x7fd7f749db02 "\"h")
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/dwarf2expr.c:954
#6  0x0000000000603a24 in dwarf_expr_eval (ctx=ctx@entry=0x1748db0, 
    addr=addr@entry=0x7fd7f749daff "\221\340|\"h", len=len@entry=3)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/dwarf2expr.c:364
#7  0x0000000000604994 in dwarf2_evaluate_loc_desc_full (type=0x24977f0, 
    frame=0x2409e00, data=0x7fd7f749daff "\221\340|\"h", size=3, 
    per_cu=0xfd3490, byte_offset=0)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/dwarf2loc.c:2251
#8  0x000000000053576a in default_read_var_value (var=0x24c29e0, 
    frame=0x2409e00) at /home/zumbi/gdb-7.7.1+dfsg/gdb/findvar.c:439
#9  0x000000000058b264 in read_frame_arg (sym=sym@entry=0x24c29e0, 
    frame=frame@entry=0x2409e00, argp=argp@entry=0x7fff3f753370, 
    entryargp=entryargp@entry=0x7fff3f753390)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/stack.c:345
#10 0x000000000058bbfd in print_frame_args (func=<optimized out>, 
    frame=frame@entry=0x2409e00, num=num@entry=-1, stream=0xf4a410)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/stack.c:672
#11 0x000000000058c59f in print_frame (frame=0x2409e00, 
    print_level=<optimized out>, print_what=SRC_AND_LOC, print_args=1, sal=...)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/stack.c:1203
#12 0x000000000058ca8f in print_frame_info (frame=0x2409e00, print_level=1, 
    print_what=SRC_AND_LOC, print_args=-1029483744, print_args@entry=1, 
    set_current_sal=1) at /home/zumbi/gdb-7.7.1+dfsg/gdb/stack.c:855
#13 0x000000000058cc7f in print_stack_frame (frame=0x2409e00, print_level=1, 
    print_what=SRC_AND_LOC, set_current_sal=1)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/stack.c:170
#14 0x0000000000653acf in execute_command (p=<optimized out>, 
    p@entry=0xdbc230 "up", from_tty=1)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/top.c:468
#15 0x000000000059c335 in command_handler (command=0xdbc230 "up")
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/event-top.c:435
#16 0x000000000059c8f4 in command_line_handler (rl=<optimized out>)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/event-top.c:632
#17 0x0000003fca22d52e in rl_callback_read_char ()
   from /lib/x86_64-linux-gnu/libreadline.so.6
#18 0x000000000059c399 in rl_callback_read_char_wrapper (
    client_data=<optimized out>)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/event-top.c:164
#19 0x000000000059ae71 in process_event ()
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/event-loop.c:342
#20 0x000000000059b2b7 in gdb_do_one_event ()
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/event-loop.c:406
#21 0x000000000059b4de in start_event_loop ()
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/event-loop.c:431
#22 0x00000000005949d3 in captured_command_loop (data=data@entry=0x0)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/main.c:267
#23 0x0000000000592a8a in catch_errors (
    func=func@entry=0x5949c0 <captured_command_loop>, 
    func_args=func_args@entry=0x0, errstring=errstring@entry=0x73fcf5 "", 
    mask=mask@entry=RETURN_MASK_ALL)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/exceptions.c:524
#24 0x0000000000595896 in captured_main (data=data@entry=0x7fff3f7539f0)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/main.c:1067
#25 0x0000000000592a8a in catch_errors (
    func=func@entry=0x594d70 <captured_main>, 
    func_args=func_args@entry=0x7fff3f7539f0, 
    errstring=errstring@entry=0x73fcf5 "", mask=mask@entry=RETURN_MASK_ALL)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/exceptions.c:524
#26 0x0000000000595d64 in gdb_main (args=args@entry=0x7fff3f7539f0)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/main.c:1076
#27 0x000000000045484e in main (argc=<optimized out>, argv=<optimized out>)
    at /home/zumbi/gdb-7.7.1+dfsg/gdb/gdb.c:34

Inferior (frame #7 is the first one that triggers the display hook in
this case, and gdb crashes after displaying the opening parenthesis):

#1  0x000000000050a487 in safeRealloc (ptr=0xa593a0, size=16) at general.c:429
#2  0x000000000050a50f in wrapSafeRealloc (ptr=0xa593a0, old_size=8, 
    new_size=16) at general.c:444
#3  0x00007ffff7ed9544 in __gmpz_realloc ()
   from /home/marc/opt/maple/17/bin.X86_64_LINUX/libgmp.so
#4  0x00007ffff7ed6638 in __gmpz_mul_2exp ()
   from /home/marc/opt/maple/17/bin.X86_64_LINUX/libgmp.so
#5  0x0000003429039c4f in mpfr_get_z ()
   from /usr/lib/x86_64-linux-gnu/libmpfr.so.4
#6  0x000000342901c0f5 in mpfr_pow ()
   from /usr/lib/x86_64-linux-gnu/libmpfr.so.4
#7  0x000000000055e5fc in __tryFaithEvaluationOptimizedPow (


>> (In case someone has a better approach to suggest, here is what I am
>> trying to achieve. I am working with a library that provides a
>> version of sprintf() for its custom data structures, and I would like
>> to write a lightweight pretty-printer that reuses this sprintf().
>> Given my use cases, I don't think it is much of a problem if the
>> pretty-printer needs to be disabled to debug some issues where the
>> additional allocations are likely to interact with the actual
>> problem. And if possible I would like to avoid writing a separate
>> Python interface for the library...)
> 
> I am curious why you need to call malloc?

This was just the first thing I tried in order to obtain a buffer for
sprintf when I started experimenting with pretty-printers...

Thanks again,

-- 
Marc


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2014-09-25 12:04 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-23  8:15 [help] Calling malloc() from a Python pretty-printer Marc Mezzarobba
2014-09-25  9:35 ` Phil Muldoon
2014-09-25 12:04   ` Marc Mezzarobba

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox