From: "Martin Schröder" <gschroeder@onlinehome.de>
To: "Petr Hluzín" <petr.hluzin@gmail.com>
Cc: <brobecker@adacore.com>, <gdb@sourceware.org>
Subject: Re: Examining copied stack contents
Date: Wed, 07 Jul 2010 17:29:00 -0000 [thread overview]
Message-ID: <A495C45A54CE4B838B8D2895700FE633@igor> (raw)
In-Reply-To: <AANLkTikSUaTebyLCok1t81hNId3ZUqfLB6BsjoQa6U1m@mail.gmail.com>
Petr HluzÃn wrote:
> On 3 July 2010 12:46, Martin Schröder <gschroeder@onlinehome.de>
> wrote:
>
> In general a debugger needs at least a stack pointer and an
> instruction pointer to get a backtrace. If the function containing the
> IP uses a frame pointer (a debugger should be able to tell you that)
> then debugger needs to know the FP. Which register contains the FP
> depends on the prologue type chosen by compiler (on x86 it is always
> EBP). Command "info frame <address>" may assume IP is pointed to by
> SP. So there are at least 2 arguments (FP+SP) to be provided on any
> arch.
>
> Therefore I suspect "info frame <address>" is not general enough to be
> used in your case.
Hello everyone; and thanks to Petr and Joel.
The above comment was exactly what I needed to find a working solution
for my problem, at least as long as GDB uses Dwarf2 frame unwinding (but
it *probably* should work with the other unwinders, too).
Due to the content of the stack being an unaltered copy, it's of course
impossible for GDB to properly unwind it at its current location. Thus,
you have to copy it back to its original position. But since you almost
always want to continue your program properly later on, your first step
has to be to save the part of the stack that's going to be overwritten.
If you assume that the convenience variable "$base" is the original
address of the stack, "$length" its length and "$copyPos" the address of
the copy, you have to execute the following commands:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
gdb> set $stack = malloc($length)
gdb> p memcpy($stack, $base, $length);
gdb> p memcpy($base, $copyPos, $length);
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Of course, you should check if malloc returns something other than 0.
But for brevity's sake, I won't write down the sanity checks.
In any case, after you've backed-up the current stack and copied over
the old stack, you have to set the $epb and $eip registers to allow GDB
to understand the stack. Both should be stored within the jmp_buf struct
that's created by the setjmp() statement.
Unfortunately, due to security reasons, glibc masks the stack pointer
register (which is not needed by GDB, strangely enough) and the eip
register on Linux. Their actual values are xor-ed with a fixed pattern
and then rotated by 9 bits to the left [1]. After undoing that, you can
get the eip and all that remains to do is to fetch the ebp frame
pointer.
In my case that's simple, because due to the way the stack is copied,
the ebp register is always 9 bytes less than the "base" variable.
Otherwise, you have to dig around where the ebp is stored inside the
jmp_buf or get it from somewhere else (like I did).
Anyway, after you have the ebp and eip values, simply back them up and
set them with the following commands:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
gdb> set $ebpsave = $ebp
gdb> set $eipsave = $eip
gdb> p $ebp = 0x<Hexadecimal-EBP-Content>
gdb> p $eip = 0x<Hexadecimal-EIP-Content>
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Now, you can get a full backtrace and explore the frame details.
If you later intend to continue execution, just reset your changes:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
gdb> p $ebp = $ebpsave
gdb> p $eip = $eipsave
gdb> p memcpy($base, $stack, $length)
gdb> p free($stack)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
That's it. A bit crude since you can't exactly "just" look at it, need
to learn the correct values of ebp and eip and it only works like that
on x86, but hey, at least it *does* work. :)
Thanks again for you help!
Martin Schröder.
[1] - http://cseweb.ucsd.edu/~hovav/dist/noret.pdf Page 14
prev parent reply other threads:[~2010-07-07 17:29 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-07-03 10:48 Martin Schröder
2010-07-05 4:54 ` support biarch gcore? Jon Zhou
2010-07-05 7:12 ` Jan Kratochvil
2010-07-05 11:55 ` Mark Kettenis
2010-07-06 20:48 ` Ulrich Weigand
2010-07-06 21:29 ` Mark Kettenis
2010-07-07 12:30 ` Ulrich Weigand
2010-07-08 2:35 ` Jon Zhou
2010-07-08 11:17 ` Ulrich Weigand
2010-07-08 4:47 ` H.J. Lu
2010-07-08 5:05 ` H.J. Lu
2010-07-08 11:15 ` Ulrich Weigand
2010-07-08 13:52 ` H.J. Lu
2010-07-21 22:45 ` Joseph S. Myers
2010-07-05 18:50 ` Examining copied stack contents Petr Hluzín
2010-07-05 20:18 ` Martin Schröder
2010-07-05 20:27 ` Joel Brobecker
2010-07-07 17:29 ` Martin Schröder [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=A495C45A54CE4B838B8D2895700FE633@igor \
--to=gschroeder@onlinehome.de \
--cc=brobecker@adacore.com \
--cc=gdb@sourceware.org \
--cc=lionhead@onlinehome.de \
--cc=petr.hluzin@gmail.com \
/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