mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2024-09-29 18:09:29 +02: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
|
if (c->as->caching_policy == UNW_CACHE_NONE
|
||||||
|| get_cached_proc_info (c) < 0)
|
|| get_cached_proc_info (c) < 0)
|
||||||
#endif
|
#endif
|
||||||
/* Lookup it up the slow way... */
|
dwarf_state_record_t sr;
|
||||||
return fetch_proc_info (c, c->ip, 0);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,15 @@ establish_machine_state (struct cursor *c)
|
||||||
(*access_reg) (as, reg, &val, 1, arg);
|
(*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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,15 @@ establish_machine_state (struct cursor *c)
|
||||||
(*access_reg) (as, reg, &val, 1, arg);
|
(*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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue