summaryrefslogtreecommitdiff
path: root/src/x86/Gos-linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/x86/Gos-linux.c')
-rw-r--r--src/x86/Gos-linux.c107
1 files changed, 107 insertions, 0 deletions
diff --git a/src/x86/Gos-linux.c b/src/x86/Gos-linux.c
index 63888a5c..529c6270 100644
--- a/src/x86/Gos-linux.c
+++ b/src/x86/Gos-linux.c
@@ -135,3 +135,110 @@ unw_handle_signal_frame (unw_cursor_t *cursor)
return 0;
}
+
+HIDDEN dwarf_loc_t
+x86_get_scratch_loc (struct cursor *c, unw_regnum_t reg)
+{
+ unw_word_t addr = c->sigcontext_addr, fpstate_addr, off;
+ int ret, is_fpstate = 0;
+
+ switch (c->sigcontext_format)
+ {
+ case X86_SCF_NONE:
+ return DWARF_REG_LOC (&c->dwarf, reg);
+
+ case X86_SCF_LINUX_SIGFRAME:
+ break;
+
+ case X86_SCF_LINUX_RT_SIGFRAME:
+ addr += LINUX_UC_MCONTEXT_OFF;
+ break;
+ }
+
+ switch (reg)
+ {
+ case UNW_X86_GS: off = LINUX_SC_GS_OFF; break;
+ case UNW_X86_FS: off = LINUX_SC_FS_OFF; break;
+ case UNW_X86_ES: off = LINUX_SC_ES_OFF; break;
+ case UNW_X86_DS: off = LINUX_SC_DS_OFF; break;
+ case UNW_X86_EDI: off = LINUX_SC_EDI_OFF; break;
+ case UNW_X86_ESI: off = LINUX_SC_ESI_OFF; break;
+ case UNW_X86_EBP: off = LINUX_SC_EBP_OFF; break;
+ case UNW_X86_ESP: off = LINUX_SC_ESP_OFF; break;
+ case UNW_X86_EBX: off = LINUX_SC_EBX_OFF; break;
+ case UNW_X86_EDX: off = LINUX_SC_EDX_OFF; break;
+ case UNW_X86_ECX: off = LINUX_SC_ECX_OFF; break;
+ case UNW_X86_EAX: off = LINUX_SC_EAX_OFF; break;
+ case UNW_X86_TRAPNO: off = LINUX_SC_TRAPNO_OFF; break;
+ case UNW_X86_EIP: off = LINUX_SC_EIP_OFF; break;
+ case UNW_X86_CS: off = LINUX_SC_CS_OFF; break;
+ case UNW_X86_EFLAGS: off = LINUX_SC_EFLAGS_OFF; break;
+ case UNW_X86_SS: off = LINUX_SC_SS_OFF; break;
+
+ /* The following is probably not correct for all possible cases.
+ Somebody who understands this better should review this for
+ correctness. */
+
+ case UNW_X86_FCW: is_fpstate = 1; off = LINUX_FPSTATE_CW_OFF; break;
+ case UNW_X86_FSW: is_fpstate = 1; off = LINUX_FPSTATE_SW_OFF; break;
+ case UNW_X86_FTW: is_fpstate = 1; off = LINUX_FPSTATE_TAG_OFF; break;
+ case UNW_X86_FCS: is_fpstate = 1; off = LINUX_FPSTATE_CSSEL_OFF; break;
+ case UNW_X86_FIP: is_fpstate = 1; off = LINUX_FPSTATE_IPOFF_OFF; break;
+ case UNW_X86_FEA: is_fpstate = 1; off = LINUX_FPSTATE_DATAOFF_OFF; break;
+ case UNW_X86_FDS: is_fpstate = 1; off = LINUX_FPSTATE_DATASEL_OFF; break;
+ case UNW_X86_MXCSR: is_fpstate = 1; off = LINUX_FPSTATE_MXCSR_OFF; break;
+
+ /* stacked fp registers */
+ case UNW_X86_ST0: case UNW_X86_ST1: case UNW_X86_ST2: case UNW_X86_ST3:
+ case UNW_X86_ST4: case UNW_X86_ST5: case UNW_X86_ST6: case UNW_X86_ST7:
+ is_fpstate = 1;
+ off = LINUX_FPSTATE_ST0_OFF + 10*(reg - UNW_X86_ST0);
+ break;
+
+ /* SSE fp registers */
+ case UNW_X86_XMM0_lo: case UNW_X86_XMM0_hi:
+ case UNW_X86_XMM1_lo: case UNW_X86_XMM1_hi:
+ case UNW_X86_XMM2_lo: case UNW_X86_XMM2_hi:
+ case UNW_X86_XMM3_lo: case UNW_X86_XMM3_hi:
+ case UNW_X86_XMM4_lo: case UNW_X86_XMM4_hi:
+ case UNW_X86_XMM5_lo: case UNW_X86_XMM5_hi:
+ case UNW_X86_XMM6_lo: case UNW_X86_XMM6_hi:
+ case UNW_X86_XMM7_lo: case UNW_X86_XMM7_hi:
+ is_fpstate = 1;
+ off = LINUX_FPSTATE_XMM0_OFF + 8*(reg - UNW_X86_XMM0_lo);
+ break;
+ case UNW_X86_XMM0:
+ case UNW_X86_XMM1:
+ case UNW_X86_XMM2:
+ case UNW_X86_XMM3:
+ case UNW_X86_XMM4:
+ case UNW_X86_XMM5:
+ case UNW_X86_XMM6:
+ case UNW_X86_XMM7:
+ is_fpstate = 1;
+ off = LINUX_FPSTATE_XMM0_OFF + 16*(reg - UNW_X86_XMM0);
+ break;
+
+ case UNW_X86_FOP:
+ case UNW_X86_TSS:
+ case UNW_X86_LDT:
+ default:
+ return DWARF_REG_LOC (&c->dwarf, reg);
+ }
+
+ if (is_fpstate)
+ {
+ if ((ret = dwarf_get (&c->dwarf,
+ DWARF_MEM_LOC (&c->dwarf,
+ addr + LINUX_SC_FPSTATE_OFF),
+ &fpstate_addr)) < 0)
+ return DWARF_NULL_LOC;
+
+ if (!fpstate_addr)
+ return DWARF_NULL_LOC;
+
+ return DWARF_MEM_LOC (c, fpstate_addr + off);
+ }
+ else
+ return DWARF_MEM_LOC (c, addr + off);
+}