mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2024-11-17 13:47:37 +01:00
dwarf: Correct handling of DW_CFA_GNU_args_size
When resuming execution, DW_CFA_GNU_args_size from the current frame must be added back to the stack pointer. Clang now generates these frequently at -O3. A simple repro for x86_64, that will crash with clang ~3.9 or newer: void f(int, int,int,int,int,int,int,int,int); int main() { try { f(0,1,2,3,4,5,6,7,8); } catch (int) { return 0; } return 1; } Where f is something that throws an int, but in a different translation unit to prevent optimization. This results in cfi instructions before the call: .cfi_escape 0x2e, 0x20 Grabbing the args_size means fully parsing the cfi in the current frame, which is unfortunate because it means nearly twice the work at each step. The logic to grab args_size can be in unw_step or get_proc_info (since this is always called before resuming in stack unwinding). Putting it in get_proc_info allows the more common unw_step code to remain fast. It would potentially fit in nicely with a proc info cache (as mentioned in the if0 comment block)
This commit is contained in:
parent
f7fe1c9a7e
commit
4b63a536ee
3 changed files with 32 additions and 2 deletions
|
@ -925,7 +925,19 @@ dwarf_make_proc_info (struct dwarf_cursor *c)
|
|||
if (c->as->caching_policy == UNW_CACHE_NONE
|
||||
|| get_cached_proc_info (c) < 0)
|
||||
#endif
|
||||
/* Lookup it up the slow way... */
|
||||
return fetch_proc_info (c, c->ip, 0);
|
||||
dwarf_state_record_t sr;
|
||||
int ret;
|
||||
|
||||
/* Lookup it up the slow way... */
|
||||
if ((ret = fetch_proc_info (c, c->ip, 1)) < 0)
|
||||
return ret;
|
||||
/* Also need to check if current frame contains
|
||||
args_size, and set cursor appropriatly. Only
|
||||
needed for unw_resume */
|
||||
if ((ret = dwarf_create_state_record (c, &sr)) < 0)
|
||||
return ret;
|
||||
put_unwind_info (c, &c->pi);
|
||||
c->args_size = sr.args_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -63,6 +63,15 @@ establish_machine_state (struct cursor *c)
|
|||
(*access_reg) (as, reg, &val, 1, arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (c->dwarf.args_size)
|
||||
{
|
||||
if (tdep_access_reg (c, ESP, &val, 0) >= 0)
|
||||
{
|
||||
val += c->dwarf.args_size;
|
||||
(*access_reg) (as, ESP, &val, 1, arg);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -95,6 +95,15 @@ establish_machine_state (struct cursor *c)
|
|||
(*access_reg) (as, reg, &val, 1, arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (c->dwarf.args_size)
|
||||
{
|
||||
if (tdep_access_reg (c, RSP, &val, 0) >= 0)
|
||||
{
|
||||
val += c->dwarf.args_size;
|
||||
(*access_reg) (as, RSP, &val, 1, arg);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue