Detect end-of-unwind

According to LibUnwind:src/x86_64/Gstep.c:85
(HEAD=c91974f30feac05055621e33ca101a371236c786), the x86_64 ABI states
that the end of the call stack is determined by either a null RBP or an
undefined return-address column in the DWARF.
This commit is contained in:
Théophile Bastian 2018-04-06 19:05:38 +02:00
parent e567039227
commit 0eb6cad1ba
3 changed files with 22 additions and 8 deletions

View file

@ -81,6 +81,8 @@ class DwarfInterpret {
/// Thrown when a Dwarf element is not found for a given PC
class OF_WHAT_EXCEPTION(NotFound);
/// Thrown when trying to unwind a context with nothing more to unwind
class FirstUnwindFrame: public std::exception {};
/// A Dwarf register
typedef dwarf::core::FrameSection::register_def DwarfRegister;
@ -172,7 +174,10 @@ class DwarfInterpret {
*/
static UnwindContext get_current_unwind_context();
/// Unwinds once the given context
/** Unwinds once the given context
*
* \throws FirstUnwindFrame when trying to unwind the first frame.
*/
UnwindContext unwind_context(const UnwindContext& ctx);
private:

View file

@ -220,15 +220,24 @@ DwarfInterpret::UnwindContext DwarfInterpret::unwind_context(
<< cie.get_return_address_register_rule()
<< " at current IP = "
<< hex << ctx.rip << endl;
new_context.rip = interpret_dw_register(
cur_row,
cie.get_return_address_register_rule(),
ctx);
try {
new_context.rip = interpret_dw_register(
cur_row,
cie.get_return_address_register_rule(),
ctx);
} catch(const std::out_of_range& e) {
// An undefined RA means we've reached the end of the call stack
throw FirstUnwindFrame();
}
cerr << "Yielding " << hex << new_context.rip << dec << endl;
new_context.rbp = interpret_dw_register(
cur_row,
lib::DWARF_X86_64_RBP,
ctx);
if(new_context.rbp == 0) {
// A null rbp means we've reached the end of the call stack
throw FirstUnwindFrame();
}
new_context.rsp = interpret_dw_register(
cur_row,

View file

@ -30,9 +30,9 @@ void dump_my_stack(int thread_id) {
cur_map_entry.pathname.c_str());
fflush(stdout);
try {
unw_context = dw.unwind_context(unw_context);
} catch(...) {
// Assume we're reached _start
unw_context = dw.unwind_context(unw_context);
} catch(const DwarfInterpret::FirstUnwindFrame& e) {
// We're reached the end of the stack
return;
}
}