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 /// Thrown when a Dwarf element is not found for a given PC
class OF_WHAT_EXCEPTION(NotFound); 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 /// A Dwarf register
typedef dwarf::core::FrameSection::register_def DwarfRegister; typedef dwarf::core::FrameSection::register_def DwarfRegister;
@ -172,7 +174,10 @@ class DwarfInterpret {
*/ */
static UnwindContext get_current_unwind_context(); 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); UnwindContext unwind_context(const UnwindContext& ctx);
private: private:

View file

@ -220,15 +220,24 @@ DwarfInterpret::UnwindContext DwarfInterpret::unwind_context(
<< cie.get_return_address_register_rule() << cie.get_return_address_register_rule()
<< " at current IP = " << " at current IP = "
<< hex << ctx.rip << endl; << hex << ctx.rip << endl;
try {
new_context.rip = interpret_dw_register( new_context.rip = interpret_dw_register(
cur_row, cur_row,
cie.get_return_address_register_rule(), cie.get_return_address_register_rule(),
ctx); 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; cerr << "Yielding " << hex << new_context.rip << dec << endl;
new_context.rbp = interpret_dw_register( new_context.rbp = interpret_dw_register(
cur_row, cur_row,
lib::DWARF_X86_64_RBP, lib::DWARF_X86_64_RBP,
ctx); 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( new_context.rsp = interpret_dw_register(
cur_row, cur_row,

View file

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