diff options
-rw-r--r-- | include/dwarf.h | 3 | ||||
-rw-r--r-- | include/libunwind_i.h | 4 | ||||
-rw-r--r-- | include/tdep-x86/dwarf-config.h | 2 | ||||
-rw-r--r-- | include/tdep-x86/libunwind_i.h | 73 | ||||
-rw-r--r-- | src/dwarf/Gparser.c | 15 | ||||
-rw-r--r-- | src/x86/Gos-freebsd.c | 1 | ||||
-rw-r--r-- | src/x86/Gregs.c | 2 | ||||
-rw-r--r-- | src/x86/Gstep.c | 4 | ||||
-rw-r--r-- | src/x86_64/Gos-freebsd.c | 1 | ||||
-rw-r--r-- | src/x86_64/Gregs.c | 2 | ||||
-rw-r--r-- | src/x86_64/Gstep.c | 2 |
11 files changed, 52 insertions, 57 deletions
diff --git a/include/dwarf.h b/include/dwarf.h index 175c419b..23ff4c4f 100644 --- a/include/dwarf.h +++ b/include/dwarf.h @@ -231,6 +231,7 @@ typedef enum DWARF_WHERE_REG, /* register saved in another register */ DWARF_WHERE_EXPR, /* register saved */ DWARF_WHERE_VAL_EXPR, /* register has computed value */ + DWARF_WHERE_CFA, /* register is set to the computed cfa value */ } dwarf_where_t; @@ -313,7 +314,7 @@ typedef struct dwarf_cursor void *as_arg; /* argument to address-space callbacks */ unw_addr_space_t as; /* reference to per-address-space info */ - unw_word_t cfa; /* canonical frame address; aka frame-/stack-pointer */ + unw_word_t cfa; /* canonical frame address; aka frame-pointer */ unw_word_t ip; /* instruction pointer */ unw_word_t args_size; /* size of arguments */ unw_word_t eh_args[UNW_TDEP_NUM_EH_REGS]; diff --git a/include/libunwind_i.h b/include/libunwind_i.h index fea5c260..6c7dda9a 100644 --- a/include/libunwind_i.h +++ b/include/libunwind_i.h @@ -346,6 +346,10 @@ static inline void invalidate_edi (struct elf_dyn_info *edi) #include "tdep/libunwind_i.h" +#ifndef TDEP_DWARF_SP +#define TDEP_DWARF_SP UNW_TDEP_SP +#endif + #ifndef tdep_get_func_addr # define tdep_get_func_addr(as,addr,v) (*(v) = addr, 0) #endif diff --git a/include/tdep-x86/dwarf-config.h b/include/tdep-x86/dwarf-config.h index f76f9c1c..11398e4e 100644 --- a/include/tdep-x86/dwarf-config.h +++ b/include/tdep-x86/dwarf-config.h @@ -43,9 +43,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ typedef struct dwarf_loc { unw_word_t val; -#ifndef UNW_LOCAL_ONLY unw_word_t type; /* see X86_LOC_TYPE_* macros. */ -#endif } dwarf_loc_t; diff --git a/include/tdep-x86/libunwind_i.h b/include/tdep-x86/libunwind_i.h index d4c5ccdb..ad4edc2f 100644 --- a/include/tdep-x86/libunwind_i.h +++ b/include/tdep-x86/libunwind_i.h @@ -84,15 +84,26 @@ dwarf_get_uc(const struct dwarf_cursor *cursor) } #define DWARF_GET_LOC(l) ((l).val) +# define DWARF_LOC_TYPE_MEM (0 << 0) +# define DWARF_LOC_TYPE_FP (1 << 0) +# define DWARF_LOC_TYPE_REG (1 << 1) +# define DWARF_LOC_TYPE_VAL (1 << 2) -#ifdef UNW_LOCAL_ONLY +# define DWARF_IS_REG_LOC(l) (((l).type & DWARF_LOC_TYPE_REG) != 0) +# define DWARF_IS_FP_LOC(l) (((l).type & DWARF_LOC_TYPE_FP) != 0) +# define DWARF_IS_MEM_LOC(l) ((l).type == DWARF_LOC_TYPE_MEM) +# define DWARF_IS_VAL_LOC(l) (((l).type & DWARF_LOC_TYPE_VAL) != 0) + +# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r), .type = (t) }) # define DWARF_NULL_LOC DWARF_LOC (0, 0) -# define DWARF_IS_NULL_LOC(l) (DWARF_GET_LOC (l) == 0) -# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r) }) -# define DWARF_IS_REG_LOC(l) 0 +# define DWARF_IS_NULL_LOC(l) \ + ({ dwarf_loc_t _l = (l); _l.val == 0 && _l.type == 0; }) +# define DWARF_VAL_LOC(c,v) DWARF_LOC ((v), DWARF_LOC_TYPE_VAL) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), DWARF_LOC_TYPE_MEM) + +#ifdef UNW_LOCAL_ONLY # define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) \ tdep_uc_addr(dwarf_get_uc(c), (r)), 0)) -# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) # define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) \ tdep_uc_addr(dwarf_get_uc(c), (r)), 0)) @@ -114,35 +125,8 @@ dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) return 0; } -static inline int -dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) -{ - if (!DWARF_GET_LOC (loc)) - return -1; - return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val, - 0, c->as_arg); -} - -static inline int -dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) -{ - if (!DWARF_GET_LOC (loc)) - return -1; - return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val, - 1, c->as_arg); -} - #else /* !UNW_LOCAL_ONLY */ -# define DWARF_LOC_TYPE_FP (1 << 0) -# define DWARF_LOC_TYPE_REG (1 << 1) -# define DWARF_NULL_LOC DWARF_LOC (0, 0) -# define DWARF_IS_NULL_LOC(l) \ - ({ dwarf_loc_t _l = (l); _l.val == 0 && _l.type == 0; }) -# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r), .type = (t) }) -# define DWARF_IS_REG_LOC(l) (((l).type & DWARF_LOC_TYPE_REG) != 0) -# define DWARF_IS_FP_LOC(l) (((l).type & DWARF_LOC_TYPE_FP) != 0) # define DWARF_REG_LOC(c,r) DWARF_LOC((r), DWARF_LOC_TYPE_REG) -# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) # define DWARF_FPREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \ | DWARF_LOC_TYPE_FP)) @@ -192,38 +176,33 @@ dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) 1, c->as_arg); } +#endif /* !UNW_LOCAL_ONLY */ + static inline int dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) { if (DWARF_IS_NULL_LOC (loc)) return -UNW_EBADREG; - /* If a code-generator were to save a value of type unw_word_t in a - floating-point register, we would have to support this case. I - suppose it could happen with MMX registers, but does it really - happen? */ - assert (!DWARF_IS_FP_LOC (loc)); - if (DWARF_IS_REG_LOC (loc)) return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), val, 0, c->as_arg); - else + if (DWARF_IS_MEM_LOC (loc)) return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val, 0, c->as_arg); + assert(DWARF_IS_VAL_LOC (loc)); + *val = DWARF_GET_LOC (loc); + return 0; } static inline int dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) { + assert(!DWARF_IS_VAL_LOC (loc)); + if (DWARF_IS_NULL_LOC (loc)) return -UNW_EBADREG; - /* If a code-generator were to save a value of type unw_word_t in a - floating-point register, we would have to support this case. I - suppose it could happen with MMX registers, but does it really - happen? */ - assert (!DWARF_IS_FP_LOC (loc)); - if (DWARF_IS_REG_LOC (loc)) return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), &val, 1, c->as_arg); @@ -232,7 +211,9 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) 1, c->as_arg); } -#endif /* !UNW_LOCAL_ONLY */ +// For historical reasons, the DWARF numbering does not match the libunwind +// numbering, necessitating this override +#define TDEP_DWARF_SP 4 #define tdep_getcontext_trace unw_getcontext #define tdep_init_done UNW_OBJ(init_done) diff --git a/src/dwarf/Gparser.c b/src/dwarf/Gparser.c index da170d4b..70a62c50 100644 --- a/src/dwarf/Gparser.c +++ b/src/dwarf/Gparser.c @@ -508,6 +508,9 @@ setup_fde (struct dwarf_cursor *c, dwarf_state_record_t *sr) for (i = 0; i < DWARF_NUM_PRESERVED_REGS + 2; ++i) set_reg (sr, i, DWARF_WHERE_SAME, 0); + // SP defaults to CFA (but is overridable) + set_reg (sr, TDEP_DWARF_SP, DWARF_WHERE_CFA, 0); + struct dwarf_cie_info *dci = c->pi.unwind_info; sr->rs_current.ret_addr_column = dci->ret_addr_column; unw_word_t addr = dci->cie_instr_start; @@ -792,14 +795,14 @@ apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs) /* As a special-case, if the stack-pointer is the CFA and the stack-pointer wasn't saved, popping the CFA implicitly pops the stack-pointer as well. */ - if ((rs->reg.val[DWARF_CFA_REG_COLUMN] == UNW_TDEP_SP) - && (UNW_TDEP_SP < ARRAY_SIZE(rs->reg.val)) - && (rs->reg.where[UNW_TDEP_SP] == DWARF_WHERE_SAME)) + if ((rs->reg.val[DWARF_CFA_REG_COLUMN] == TDEP_DWARF_SP) + && (TDEP_DWARF_SP < ARRAY_SIZE(rs->reg.val)) + && (DWARF_IS_NULL_LOC(c->loc[TDEP_DWARF_SP]))) cfa = c->cfa; else { regnum = dwarf_to_unw_regnum (rs->reg.val[DWARF_CFA_REG_COLUMN]); - if ((ret = unw_get_reg ((unw_cursor_t *) c, regnum, &cfa)) < 0) + if ((ret = unw_get_reg (dwarf_to_cursor(c), regnum, &cfa)) < 0) return ret; } cfa += rs->reg.val[DWARF_CFA_OFF_COLUMN]; @@ -836,6 +839,10 @@ apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs) case DWARF_WHERE_SAME: break; + case DWARF_WHERE_CFA: + new_loc[i] = DWARF_VAL_LOC (c, cfa); + break; + case DWARF_WHERE_CFAREL: new_loc[i] = DWARF_MEM_LOC (c, cfa + rs->reg.val[i]); break; diff --git a/src/x86/Gos-freebsd.c b/src/x86/Gos-freebsd.c index 7dd01404..1b251d02 100644 --- a/src/x86/Gos-freebsd.c +++ b/src/x86/Gos-freebsd.c @@ -138,6 +138,7 @@ x86_handle_signal_frame (unw_cursor_t *cursor) c->dwarf.loc[ST0] = DWARF_NULL_LOC; } else if (c->sigcontext_format == X86_SCF_FREEBSD_SYSCALL) { c->dwarf.loc[EIP] = DWARF_LOC (c->dwarf.cfa, 0); + c->dwarf.loc[ESP] = DWARF_VAL_LOC (c, c->dwarf.cfa + 4); c->dwarf.loc[EAX] = DWARF_NULL_LOC; c->dwarf.cfa += 4; c->dwarf.use_prev_instr = 1; diff --git a/src/x86/Gregs.c b/src/x86/Gregs.c index 4a959261..9446d6c6 100644 --- a/src/x86/Gregs.c +++ b/src/x86/Gregs.c @@ -53,7 +53,6 @@ tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, break; case UNW_X86_CFA: - case UNW_X86_ESP: if (write) return -UNW_EREADONLYREG; *valp = c->dwarf.cfa; @@ -81,6 +80,7 @@ tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, case UNW_X86_ECX: loc = c->dwarf.loc[ECX]; break; case UNW_X86_EBX: loc = c->dwarf.loc[EBX]; break; + case UNW_X86_ESP: loc = c->dwarf.loc[ESP]; break; case UNW_X86_EBP: loc = c->dwarf.loc[EBP]; break; case UNW_X86_ESI: loc = c->dwarf.loc[ESI]; break; case UNW_X86_EDI: loc = c->dwarf.loc[EDI]; break; diff --git a/src/x86/Gstep.c b/src/x86/Gstep.c index 129b739a..061dcbaa 100644 --- a/src/x86/Gstep.c +++ b/src/x86/Gstep.c @@ -47,7 +47,7 @@ unw_step (unw_cursor_t *cursor) { /* DWARF failed, let's see if we can follow the frame-chain or skip over the signal trampoline. */ - struct dwarf_loc ebp_loc, eip_loc; + struct dwarf_loc ebp_loc, eip_loc, esp_loc; /* We could get here because of missing/bad unwind information. Validate all addresses before dereferencing. */ @@ -77,6 +77,7 @@ unw_step (unw_cursor_t *cursor) c->dwarf.cfa); ebp_loc = DWARF_LOC (c->dwarf.cfa, 0); + esp_loc = DWARF_VAL_LOC (c, c->dwarf.cfa + 8); eip_loc = DWARF_LOC (c->dwarf.cfa + 4, 0); c->dwarf.cfa += 8; @@ -87,6 +88,7 @@ unw_step (unw_cursor_t *cursor) c->dwarf.loc[i] = DWARF_NULL_LOC; c->dwarf.loc[EBP] = ebp_loc; + c->dwarf.loc[ESP] = esp_loc; c->dwarf.loc[EIP] = eip_loc; c->dwarf.use_prev_instr = 1; } diff --git a/src/x86_64/Gos-freebsd.c b/src/x86_64/Gos-freebsd.c index 91a465c6..aa6a4b43 100644 --- a/src/x86_64/Gos-freebsd.c +++ b/src/x86_64/Gos-freebsd.c @@ -133,6 +133,7 @@ x86_64_handle_signal_frame (unw_cursor_t *cursor) c->dwarf.loc[RCX] = c->dwarf.loc[R10]; /* rsp_loc = DWARF_LOC(c->dwarf.cfa - 8, 0); */ /* rbp_loc = c->dwarf.loc[RBP]; */ + c->dwarf.loc[RSP] = DWARF_VAL_LOC (c, c->dwarf.cfa + 8); c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0); ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip); Debug (1, "Frame Chain [RIP=0x%Lx] = 0x%Lx\n", diff --git a/src/x86_64/Gregs.c b/src/x86_64/Gregs.c index baf8a24f..dff5bcbe 100644 --- a/src/x86_64/Gregs.c +++ b/src/x86_64/Gregs.c @@ -79,7 +79,6 @@ tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, break; case UNW_X86_64_CFA: - case UNW_X86_64_RSP: if (write) return -UNW_EREADONLYREG; *valp = c->dwarf.cfa; @@ -107,6 +106,7 @@ tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, case UNW_X86_64_RCX: loc = c->dwarf.loc[RCX]; break; case UNW_X86_64_RBX: loc = c->dwarf.loc[RBX]; break; + case UNW_X86_64_RSP: loc = c->dwarf.loc[RSP]; break; case UNW_X86_64_RBP: loc = c->dwarf.loc[RBP]; break; case UNW_X86_64_RSI: loc = c->dwarf.loc[RSI]; break; case UNW_X86_64_RDI: loc = c->dwarf.loc[RDI]; break; diff --git a/src/x86_64/Gstep.c b/src/x86_64/Gstep.c index 3c5c3830..fdad298c 100644 --- a/src/x86_64/Gstep.c +++ b/src/x86_64/Gstep.c @@ -223,7 +223,7 @@ unw_step (unw_cursor_t *cursor) Debug (2, "RIP fixup didn't work, falling back\n"); unw_word_t rbp1 = 0; rbp_loc = DWARF_LOC(rbp, 0); - rsp_loc = DWARF_NULL_LOC; + rsp_loc = DWARF_VAL_LOC(c, rbp + 16); rip_loc = DWARF_LOC (rbp + 8, 0); ret = dwarf_get (&c->dwarf, rbp_loc, &rbp1); Debug (1, "[RBP=0x%lx] = 0x%lx (cfa = 0x%lx) -> 0x%lx\n", |