Ian Lance Taylor wrote:
Roy Krischer <rkrische@xxxxxxxxxxxxxxxx> writes:
I've been playing around with _Unwind_Backtrace for a C++ project of
mine. Ideally, I would like to call the personality routine from
_Unwind_Backtrace to decode the lsda for me, and I can certainly do it
through the trace function.
The problem that I have, however, is that the unwinding that
_Unwind_Backtrace produces is different from the one
_Unwind_RaiseException produces. More specifically, the contexts
created by _Unwind_Backtrace have the first few register locations
NULLed, so when I run the personality routine in _UA_CLEANUP_PHASE
mode, it tries to dereference those (reg[0] and reg[2] on my
architecture) null pointers and crashes.
What is so fundamentally different about _Unwind_Backtrace and
_Unwind_RaiseException, that _Unwind_RaiseException produces
complete' contexts, while Backtrace does not? Is it because
_Unwind_RaiseException uses __builtin_eh_return and this causes the
compiler to generate the proper information?
How can I trick _Unwind_Backtrace into producing the same contexts
and/or using the personality routine and it behaving just like during
exception handling (minus installing the context at the end, of
course)?
In general the personality routine assumes that it is executing in an
exception region. If you are calling _Unwind_Backtrace, you may well
unwind into code which is not in an exception region. There is no
particular reason to assume that the personality routine will work in
that case.
I'm calling both from pretty much the same code, ie
try {
a();
throw xxx();
} catch (...) {}
where a() calls _Unwind_Backtrace (and throw calls RaiseException).
And the personality function per se is not the issue, but rather the
contexts that stack walking gives to it.
e.g.
this is a context as produced by Backtrace
-------
(gdb) p *context
$123 = {
reg = {0x0, 0x0, 0x0, 0x80bf058, 0x0, 0x80bf05c, 0x80bf004,
0x80bf008, 0x80bf060, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
cfa = 0x80bf064,
ra = 0x804b740,
lsda = 0x80862b0,
bases = {
tbase = 0x0,
dbase = 0x0,
func = 0x804b710
},
flags = 1073741824,
version = 0,
args_size = 0,
by_value = '\0' <repeats 17 times>
}
----------
and the same context as produced by RaiseException
-----------
p *context
$134 = {
reg = {0x80befd8, 0x0, 0x80befdc, 0x80bf058, 0x0, 0x80bf05c,
0x80bf008, 0x80befe8, 0x80bf060, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0},
cfa = 0x80bf064,
ra = 0x804b740,
lsda = 0x80862b0,
bases = {
tbase = 0x0,
dbase = 0x0,
func = 0x804b710
},
flags = 1073741824,
version = 0,
args_size = 0,
by_value = '\0' <repeats 17 times>
}
------------
Note that reg[0] and reg[2] in particular are well-defined in the latter
but NULL in the former.
It may help to use the -fasynchronous-unwind-tables option.
Tried it, no change. As mentioned, both call sequences are virtually
identical and unwind through the same regions.
Also there is a lot of architecture specific in this area, so you need
to tell us your architecture.
just your normal 32bit x86.
On this architecture, reg[0] and reg[2] are used to find the stores for
the switch value and the exception parameter. That's why it's not good
for them to be NULL.
Thanks
Roy