summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSaleem Abdulrasool <compnerd@compnerd.org>2017-01-18 13:56:19 -0800
committerDave Watson <davejwatson@fb.com>2017-01-19 10:07:53 -0800
commite9e8ed73e34a2d65c7ec71c296156637763ffd5c (patch)
tree1a137ce09bf2df4aa89697af3c02cea47f6a3832
parent9e97c9b17ae9b6922980465656b14bac5df2ea32 (diff)
downloadlibunwind-e9e8ed73e34a2d65c7ec71c296156637763ffd5c.tar.gz
dwarf: Account for multiple CFA for args_size
It is possible to have multiple CFA_args_size adjustments for a single frame. If the CFA_args_size adjustment is immediately following the return from a function which can raise an exception, it is possible to incorrectly adjust the stack pointer. Consider the following: ... .cfi_escape 0x2e, 0x00 call f .Ltmp: .cfi_escape 0x2e, 0x10 lea label@GOTOFF(%ebx), %eax ... Because we process the CFI program up to and *INCLUDING* IP, where the IP is the RA, we would process the associated DW_CFA_GNU_args_size for the post-call instruction. The result would be a DW_CFA_GNU_args_size of 0x10 rather than 0x00, resulting in an incorrect stack adjustment. Handle this by processing the CFI operation but not adjusting the state record unless we are below the current IP.
-rw-r--r--src/dwarf/Gparser.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/src/dwarf/Gparser.c b/src/dwarf/Gparser.c
index 1831a58c..3f16189a 100644
--- a/src/dwarf/Gparser.c
+++ b/src/dwarf/Gparser.c
@@ -356,8 +356,11 @@ run_cfi_program (struct dwarf_cursor *c, dwarf_state_record_t *sr,
case DW_CFA_GNU_args_size:
if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
goto fail;
- sr->args_size = val;
- Debug (15, "CFA_GNU_args_size %lu\n", (long) val);
+ if (curr_ip < ip)
+ {
+ sr->args_size = val;
+ Debug (15, "CFA_GNU_args_size %lu\n", (long) val);
+ }
break;
case DW_CFA_GNU_negative_offset_extended: