Mirror of the gdb mailing list
 help / color / mirror / Atom feed
From: G <tjmadwja@gmail.com>
To: gdb@sourceware.org
Subject: Re: Debugging variable arguments functions (stdarg)
Date: Mon, 19 Jul 2010 14:19:00 -0000	[thread overview]
Message-ID: <AANLkTik5fl5xzH0I71_I9bRAwLeS7Yt4xcGOx6NPVEXc@mail.gmail.com> (raw)
In-Reply-To: <AANLkTimfKj6_HnMIVMC6cGLq6SBtVh7gk-RXhpgsWeD4@mail.gmail.com>

On Sun, Jul 18, 2010 at 9:27 PM, Petr Hluzín <petr.hluzin@gmail.com> wrote:
> On 16 July 2010 21:12, Jan Kratochvil <jan.kratochvil@redhat.com> wrote:
>> On Fri, 16 Jul 2010 20:57:57 +0200, Petr Hluzín wrote:
>>> Workaround B:
>>> Get value of stack pointer (RSP?) of frame MysqlWrapper() and dump raw
>>> memory around the address. You should see these values somewhere
>>> around:
>>> 0x00000000004041e2 (return address in MysqlWrapper)
>>> 0x406bf0 (the third argument to WriteLog)
>>> Between these two values should be the values of 3rd and 4th argument.
>>
>> This is not so simple on x86_64, it passes even (first few) stdarg parameters
>> in registers.
>>        http://www.x86-64.org/documentation/abi.pdf
>
> Nice reading.
> I suppose it is documented section "3.5.7 Variable Argument Lists".
> Unfortunately I was not able to find any specific wording.
> But it makes sense. You are probably right.
>
> It should be possible by reading the document to determine if the two
> arguments go to stack or remained in registers. I failed to figure
> that out.
>
> Ok, this means that G has to examine stack memory of all frames - infeasible.

First, thanks for the replies. I've actually found a solution which
lets me look at the arguments passed in the "..." list without too
much effort, and thought I'd share it. A Google search for "gdb
variadic" instead of "gdb variable arguments" turned up a blog post at
http://www.moythreads.com/wordpress/2008/05/ which contained an almost
complete solution.

In case that blog post disappears, and for archiving reasons, I'm
including a very short writeup/example here. First some simple code:


#include <stdarg.h>
#include <stdio.h>

void myfunc(const char *fmt, ...)
{
        va_list args;
        va_start(args, fmt);
        vprintf(fmt, args);
        va_end(args);
        return;
}

int main(int argc, char *argv[])
{
        myfunc("test 1: %s %s\n", "one", "two");
        myfunc("test 2: %s %d %c\n", "apple", 222, 'y');
        return 0;
}


A short debugging session with some comments so that some gdb novice
like myself might get an idea of what is happening (I hope my comments
are correct...):


$ gdb testprog
GNU gdb (GDB) 7.1-debian
[snip]
Reading symbols from /home/user/testprog...done.
(gdb) break myfunc
Breakpoint 1 at 0x400552: file testprog.c, line 7.
(gdb) run
Starting program: /home/user/testprog

Breakpoint 1, myfunc (fmt=0x4006f4 "test 1: %s %s\n") at testprog.c:7
7               va_start(args, fmt);
(gdb) # initialize args to hold correct values:
(gdb) step
8               vprintf(fmt, args);
(gdb) # print first argument in "..." list which we know is a char*:
(gdb) p *(char **)(((char *)args[0].reg_save_area)+args[0].gp_offset)
$1 = 0x4006f0 "one"
(gdb) # print first byte in argument in "..." list which we know is a char*:
(gdb) p **(char **)(((char *)args[0].reg_save_area)+args[0].gp_offset)
$2 = 111 'o'
(gdb) # print first byte in second argument in "..." list which is also a char*
(gdb) # (we use +8 since this is a 64-bit machine):
(gdb) p **(char **)(((char *)args[0].reg_save_area)+args[0].gp_offset+8)
$3 = 116 't'
(gdb) # print second argument in "..." list:
(gdb) p *(char **)(((char *)args[0].reg_save_area)+args[0].gp_offset+8)
$4 = 0x4006ec "two"
(gdb) # look at what lies beyond:
(gdb) p *(long *)(((char *)args[0].reg_save_area)+args[0].gp_offset+16)
$5 = 0
(gdb) # step program to execute the vprintf() call:
(gdb) next
test 1: one two
11      }
(gdb) # return to main():
(gdb) next
main (argc=1, argv=0x7fffffffeb58) at testprog.c:16
16              myfunc("test 2: %s %d %c\n", "apple", 222, 'y');
(gdb) # execute call to myfunc() a second time with different arguments:
(gdb) next

Breakpoint 1, myfunc (fmt=0x400715 "test 2: %s %s %s\n") at testprog.c:7
7               va_start(args, fmt);
(gdb) # initialize args to hold correct values:
(gdb) step
8               vprintf(fmt, args);
(gdb) # print first argument in "..." list which again we know is a char*:
(gdb) p *(char **)(((char *)args[0].reg_save_area)+args[0].gp_offset)
$6 = 0x40070f "apple"
(gdb) # print second argument in "..." list which is an int:
(gdb) p *(int *)(((char *)args[0].reg_save_area)+args[0].gp_offset+8)
$7 = 222
(gdb) # print third argument in "..." list which is a char:
(gdb) p *(char *)(((char *)args[0].reg_save_area)+args[0].gp_offset+16)
$8 = 121 'y'
(gdb) # look at what lies beyond:
(gdb) p *(long *)(((char *)args[0].reg_save_area)+args[0].gp_offset+24)
$9 = 1
(gdb) # OK, so the 0 at the end of the last "..." list seems like just a
(gdb) # coincidence, not an intentional NULL value.
(gdb) # let program finish:
(gdb) cont
Continuing.
test 2: apple 222 y

Program exited normally.
(gdb)


      reply	other threads:[~2010-07-19 14:19 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-07-15 15:47 G
2010-07-16 18:57 ` Michael Snyder
2010-07-16 18:58 ` Petr Hluzín
2010-07-16 19:12   ` Jan Kratochvil
2010-07-18 19:28     ` Petr Hluzín
2010-07-19 14:19       ` G [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=AANLkTik5fl5xzH0I71_I9bRAwLeS7Yt4xcGOx6NPVEXc@mail.gmail.com \
    --to=tjmadwja@gmail.com \
    --cc=gdb@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox