Gregs.c revision e9cd30040e2794ee586ff853b360b47881824fda
1/* libunwind - a platform-independent unwind library 2 Copyright (c) 2002-2004 Hewlett-Packard Development Company, L.P. 3 Contributed by David Mosberger-Tang <davidm@hpl.hp.com> 4 5This file is part of libunwind. 6 7Permission is hereby granted, free of charge, to any person obtaining 8a copy of this software and associated documentation files (the 9"Software"), to deal in the Software without restriction, including 10without limitation the rights to use, copy, modify, merge, publish, 11distribute, sublicense, and/or sell copies of the Software, and to 12permit persons to whom the Software is furnished to do so, subject to 13the following conditions: 14 15The above copyright notice and this permission notice shall be 16included in all copies or substantial portions of the Software. 17 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 25 26#include "offsets.h" 27#include "unwind_i.h" 28 29#if defined __linux__ 30static inline dwarf_loc_t 31get_scratch_loc (struct cursor *c, unw_regnum_t reg) 32{ 33 unw_word_t addr = c->sigcontext_addr, fpstate_addr, off; 34 int ret, is_fpstate = 0; 35 36 switch (c->sigcontext_format) 37 { 38 case X86_SCF_NONE: 39 return DWARF_REG_LOC (&c->dwarf, reg); 40 41 case X86_SCF_LINUX_SIGFRAME: 42 break; 43 44 case X86_SCF_LINUX_RT_SIGFRAME: 45 addr += LINUX_UC_MCONTEXT_OFF; 46 break; 47 } 48 49 switch (reg) 50 { 51 case UNW_X86_GS: off = LINUX_SC_GS_OFF; break; 52 case UNW_X86_FS: off = LINUX_SC_FS_OFF; break; 53 case UNW_X86_ES: off = LINUX_SC_ES_OFF; break; 54 case UNW_X86_DS: off = LINUX_SC_DS_OFF; break; 55 case UNW_X86_EDI: off = LINUX_SC_EDI_OFF; break; 56 case UNW_X86_ESI: off = LINUX_SC_ESI_OFF; break; 57 case UNW_X86_EBP: off = LINUX_SC_EBP_OFF; break; 58 case UNW_X86_ESP: off = LINUX_SC_ESP_OFF; break; 59 case UNW_X86_EBX: off = LINUX_SC_EBX_OFF; break; 60 case UNW_X86_EDX: off = LINUX_SC_EDX_OFF; break; 61 case UNW_X86_ECX: off = LINUX_SC_ECX_OFF; break; 62 case UNW_X86_EAX: off = LINUX_SC_EAX_OFF; break; 63 case UNW_X86_TRAPNO: off = LINUX_SC_TRAPNO_OFF; break; 64 case UNW_X86_EIP: off = LINUX_SC_EIP_OFF; break; 65 case UNW_X86_CS: off = LINUX_SC_CS_OFF; break; 66 case UNW_X86_EFLAGS: off = LINUX_SC_EFLAGS_OFF; break; 67 case UNW_X86_SS: off = LINUX_SC_SS_OFF; break; 68 69 /* The following is probably not correct for all possible cases. 70 Somebody who understands this better should review this for 71 correctness. */ 72 73 case UNW_X86_FCW: is_fpstate = 1; off = LINUX_FPSTATE_CW_OFF; break; 74 case UNW_X86_FSW: is_fpstate = 1; off = LINUX_FPSTATE_SW_OFF; break; 75 case UNW_X86_FTW: is_fpstate = 1; off = LINUX_FPSTATE_TAG_OFF; break; 76 case UNW_X86_FCS: is_fpstate = 1; off = LINUX_FPSTATE_CSSEL_OFF; break; 77 case UNW_X86_FIP: is_fpstate = 1; off = LINUX_FPSTATE_IPOFF_OFF; break; 78 case UNW_X86_FEA: is_fpstate = 1; off = LINUX_FPSTATE_DATAOFF_OFF; break; 79 case UNW_X86_FDS: is_fpstate = 1; off = LINUX_FPSTATE_DATASEL_OFF; break; 80 case UNW_X86_MXCSR: is_fpstate = 1; off = LINUX_FPSTATE_MXCSR_OFF; break; 81 82 /* stacked fp registers */ 83 case UNW_X86_ST0: case UNW_X86_ST1: case UNW_X86_ST2: case UNW_X86_ST3: 84 case UNW_X86_ST4: case UNW_X86_ST5: case UNW_X86_ST6: case UNW_X86_ST7: 85 is_fpstate = 1; 86 off = LINUX_FPSTATE_ST0_OFF + 10*(reg - UNW_X86_ST0); 87 break; 88 89 /* SSE fp registers */ 90 case UNW_X86_XMM0_lo: case UNW_X86_XMM0_hi: 91 case UNW_X86_XMM1_lo: case UNW_X86_XMM1_hi: 92 case UNW_X86_XMM2_lo: case UNW_X86_XMM2_hi: 93 case UNW_X86_XMM3_lo: case UNW_X86_XMM3_hi: 94 case UNW_X86_XMM4_lo: case UNW_X86_XMM4_hi: 95 case UNW_X86_XMM5_lo: case UNW_X86_XMM5_hi: 96 case UNW_X86_XMM6_lo: case UNW_X86_XMM6_hi: 97 case UNW_X86_XMM7_lo: case UNW_X86_XMM7_hi: 98 is_fpstate = 1; 99 off = LINUX_FPSTATE_XMM0_OFF + 8*(reg - UNW_X86_XMM0_lo); 100 break; 101 case UNW_X86_XMM0: 102 case UNW_X86_XMM1: 103 case UNW_X86_XMM2: 104 case UNW_X86_XMM3: 105 case UNW_X86_XMM4: 106 case UNW_X86_XMM5: 107 case UNW_X86_XMM6: 108 case UNW_X86_XMM7: 109 is_fpstate = 1; 110 off = LINUX_FPSTATE_XMM0_OFF + 16*(reg - UNW_X86_XMM0); 111 break; 112 113 case UNW_X86_FOP: 114 case UNW_X86_TSS: 115 case UNW_X86_LDT: 116 default: 117 return DWARF_REG_LOC (&c->dwarf, reg); 118 } 119 120 if (is_fpstate) 121 { 122 if ((ret = dwarf_get (&c->dwarf, 123 DWARF_MEM_LOC (&c->dwarf, 124 addr + LINUX_SC_FPSTATE_OFF), 125 &fpstate_addr)) < 0) 126 return DWARF_NULL_LOC; 127 128 if (!fpstate_addr) 129 return DWARF_NULL_LOC; 130 131 return DWARF_MEM_LOC (c, fpstate_addr + off); 132 } 133 else 134 return DWARF_MEM_LOC (c, addr + off); 135} 136#elif defined __FreeBSD__ 137static inline dwarf_loc_t 138get_scratch_loc (struct cursor *c, unw_regnum_t reg) 139{ 140 unw_word_t addr = c->sigcontext_addr, fpstate_addr, off; 141 int ret, is_fpstate = 0; 142 143 switch (c->sigcontext_format) 144 { 145 case X86_SCF_NONE: 146 return DWARF_REG_LOC (&c->dwarf, reg); 147 148 case X86_SCF_FREEBSD_SIGFRAME: 149 addr += FREEBSD_UC_MCONTEXT_OFF; 150 break; 151 152 case X86_SCF_FREEBSD_SIGFRAME4: 153 abort(); 154 break; 155 156 case X86_SCF_FREEBSD_OSIGFRAME: 157 /* XXXKIB */ 158 abort(); 159 break; 160 161 case X86_SCF_FREEBSD_SYSCALL: 162 /* XXXKIB */ 163 abort(); 164 break; 165 166 default: 167 /* XXXKIB */ 168 abort(); 169 break; 170 } 171 172 switch (reg) 173 { 174 case UNW_X86_GS: off = FREEBSD_UC_MCONTEXT_GS_OFF; break; 175 case UNW_X86_FS: off = FREEBSD_UC_MCONTEXT_FS_OFF; break; 176 case UNW_X86_ES: off = FREEBSD_UC_MCONTEXT_ES_OFF; break; 177 case UNW_X86_DS: off = FREEBSD_UC_MCONTEXT_SS_OFF; break; 178 case UNW_X86_EDI: off = FREEBSD_UC_MCONTEXT_EDI_OFF; break; 179 case UNW_X86_ESI: off = FREEBSD_UC_MCONTEXT_ESI_OFF; break; 180 case UNW_X86_EBP: off = FREEBSD_UC_MCONTEXT_EBP_OFF; break; 181 case UNW_X86_ESP: off = FREEBSD_UC_MCONTEXT_ESP_OFF; break; 182 case UNW_X86_EBX: off = FREEBSD_UC_MCONTEXT_EBX_OFF; break; 183 case UNW_X86_EDX: off = FREEBSD_UC_MCONTEXT_EDX_OFF; break; 184 case UNW_X86_ECX: off = FREEBSD_UC_MCONTEXT_ECX_OFF; break; 185 case UNW_X86_EAX: off = FREEBSD_UC_MCONTEXT_EAX_OFF; break; 186 case UNW_X86_TRAPNO: off = FREEBSD_UC_MCONTEXT_TRAPNO_OFF; break; 187 case UNW_X86_EIP: off = FREEBSD_UC_MCONTEXT_EIP_OFF; break; 188 case UNW_X86_CS: off = FREEBSD_UC_MCONTEXT_CS_OFF; break; 189 case UNW_X86_EFLAGS: off = FREEBSD_UC_MCONTEXT_EFLAGS_OFF; break; 190 case UNW_X86_SS: off = FREEBSD_UC_MCONTEXT_SS_OFF; break; 191 192 /* The following is probably not correct for all possible cases. 193 Somebody who understands this better should review this for 194 correctness. */ 195 196 case UNW_X86_FCW: is_fpstate = 1; off = LINUX_FPSTATE_CW_OFF; break; 197 case UNW_X86_FSW: is_fpstate = 1; off = LINUX_FPSTATE_SW_OFF; break; 198 case UNW_X86_FTW: is_fpstate = 1; off = LINUX_FPSTATE_TAG_OFF; break; 199 case UNW_X86_FCS: is_fpstate = 1; off = LINUX_FPSTATE_CSSEL_OFF; break; 200 case UNW_X86_FIP: is_fpstate = 1; off = LINUX_FPSTATE_IPOFF_OFF; break; 201 case UNW_X86_FEA: is_fpstate = 1; off = LINUX_FPSTATE_DATAOFF_OFF; break; 202 case UNW_X86_FDS: is_fpstate = 1; off = LINUX_FPSTATE_DATASEL_OFF; break; 203 case UNW_X86_MXCSR: is_fpstate = 1; off = LINUX_FPSTATE_MXCSR_OFF; break; 204 205 /* stacked fp registers */ 206 case UNW_X86_ST0: case UNW_X86_ST1: case UNW_X86_ST2: case UNW_X86_ST3: 207 case UNW_X86_ST4: case UNW_X86_ST5: case UNW_X86_ST6: case UNW_X86_ST7: 208 is_fpstate = 1; 209 off = LINUX_FPSTATE_ST0_OFF + 10*(reg - UNW_X86_ST0); 210 break; 211 212 /* SSE fp registers */ 213 case UNW_X86_XMM0_lo: case UNW_X86_XMM0_hi: 214 case UNW_X86_XMM1_lo: case UNW_X86_XMM1_hi: 215 case UNW_X86_XMM2_lo: case UNW_X86_XMM2_hi: 216 case UNW_X86_XMM3_lo: case UNW_X86_XMM3_hi: 217 case UNW_X86_XMM4_lo: case UNW_X86_XMM4_hi: 218 case UNW_X86_XMM5_lo: case UNW_X86_XMM5_hi: 219 case UNW_X86_XMM6_lo: case UNW_X86_XMM6_hi: 220 case UNW_X86_XMM7_lo: case UNW_X86_XMM7_hi: 221 is_fpstate = 1; 222 off = LINUX_FPSTATE_XMM0_OFF + 8*(reg - UNW_X86_XMM0_lo); 223 break; 224 case UNW_X86_XMM0: 225 case UNW_X86_XMM1: 226 case UNW_X86_XMM2: 227 case UNW_X86_XMM3: 228 case UNW_X86_XMM4: 229 case UNW_X86_XMM5: 230 case UNW_X86_XMM6: 231 case UNW_X86_XMM7: 232 is_fpstate = 1; 233 off = LINUX_FPSTATE_XMM0_OFF + 16*(reg - UNW_X86_XMM0); 234 break; 235 236 case UNW_X86_FOP: 237 case UNW_X86_TSS: 238 case UNW_X86_LDT: 239 default: 240 return DWARF_REG_LOC (&c->dwarf, reg); 241 } 242 243 if (is_fpstate) 244 { 245 if ((ret = dwarf_get (&c->dwarf, 246 DWARF_MEM_LOC (&c->dwarf, 247 addr + LINUX_SC_FPSTATE_OFF), 248 &fpstate_addr)) < 0) 249 return DWARF_NULL_LOC; 250 251 if (!fpstate_addr) 252 return DWARF_NULL_LOC; 253 254 return DWARF_MEM_LOC (c, fpstate_addr + off); 255 } 256 else 257 return DWARF_MEM_LOC (c, addr + off); 258} 259#else 260#error Port me 261#endif 262 263HIDDEN dwarf_loc_t 264x86_scratch_loc (struct cursor *c, unw_regnum_t reg) 265{ 266 if (c->sigcontext_addr) 267 return get_scratch_loc (c, reg); 268 else 269 return DWARF_REG_LOC (&c->dwarf, reg); 270} 271 272HIDDEN int 273tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, 274 int write) 275{ 276 dwarf_loc_t loc = DWARF_NULL_LOC; 277 unsigned int mask; 278 int arg_num; 279 280 switch (reg) 281 { 282 283 case UNW_X86_EIP: 284 if (write) 285 c->dwarf.ip = *valp; /* also update the EIP cache */ 286 loc = c->dwarf.loc[EIP]; 287 break; 288 289 case UNW_X86_CFA: 290 case UNW_X86_ESP: 291 if (write) 292 return -UNW_EREADONLYREG; 293 *valp = c->dwarf.cfa; 294 return 0; 295 296 case UNW_X86_EAX: 297 case UNW_X86_EDX: 298 arg_num = reg - UNW_X86_EAX; 299 mask = (1 << arg_num); 300 if (write) 301 { 302 c->dwarf.eh_args[arg_num] = *valp; 303 c->dwarf.eh_valid_mask |= mask; 304 return 0; 305 } 306 else if ((c->dwarf.eh_valid_mask & mask) != 0) 307 { 308 *valp = c->dwarf.eh_args[arg_num]; 309 return 0; 310 } 311 else 312 loc = c->dwarf.loc[(reg == UNW_X86_EAX) ? EAX : EDX]; 313 break; 314 315 case UNW_X86_ECX: loc = c->dwarf.loc[ECX]; break; 316 case UNW_X86_EBX: loc = c->dwarf.loc[EBX]; break; 317 318 case UNW_X86_EBP: loc = c->dwarf.loc[EBP]; break; 319 case UNW_X86_ESI: loc = c->dwarf.loc[ESI]; break; 320 case UNW_X86_EDI: loc = c->dwarf.loc[EDI]; break; 321 case UNW_X86_EFLAGS: loc = c->dwarf.loc[EFLAGS]; break; 322 case UNW_X86_TRAPNO: loc = c->dwarf.loc[TRAPNO]; break; 323 324 case UNW_X86_FCW: 325 case UNW_X86_FSW: 326 case UNW_X86_FTW: 327 case UNW_X86_FOP: 328 case UNW_X86_FCS: 329 case UNW_X86_FIP: 330 case UNW_X86_FEA: 331 case UNW_X86_FDS: 332 case UNW_X86_MXCSR: 333 case UNW_X86_GS: 334 case UNW_X86_FS: 335 case UNW_X86_ES: 336 case UNW_X86_DS: 337 case UNW_X86_SS: 338 case UNW_X86_CS: 339 case UNW_X86_TSS: 340 case UNW_X86_LDT: 341 loc = x86_scratch_loc (c, reg); 342 break; 343 344 default: 345 Debug (1, "bad register number %u\n", reg); 346 return -UNW_EBADREG; 347 } 348 349 if (write) 350 return dwarf_put (&c->dwarf, loc, *valp); 351 else 352 return dwarf_get (&c->dwarf, loc, valp); 353} 354 355HIDDEN int 356tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, unw_fpreg_t *valp, 357 int write) 358{ 359 struct dwarf_loc loc = DWARF_NULL_LOC; 360 361 switch (reg) 362 { 363 case UNW_X86_ST0: 364 loc = c->dwarf.loc[ST0]; 365 break; 366 367 /* stacked fp registers */ 368 case UNW_X86_ST1: 369 case UNW_X86_ST2: 370 case UNW_X86_ST3: 371 case UNW_X86_ST4: 372 case UNW_X86_ST5: 373 case UNW_X86_ST6: 374 case UNW_X86_ST7: 375 /* SSE fp registers */ 376 case UNW_X86_XMM0: 377 case UNW_X86_XMM1: 378 case UNW_X86_XMM2: 379 case UNW_X86_XMM3: 380 case UNW_X86_XMM4: 381 case UNW_X86_XMM5: 382 case UNW_X86_XMM6: 383 case UNW_X86_XMM7: 384 case UNW_X86_XMM0_lo: 385 case UNW_X86_XMM0_hi: 386 case UNW_X86_XMM1_lo: 387 case UNW_X86_XMM1_hi: 388 case UNW_X86_XMM2_lo: 389 case UNW_X86_XMM2_hi: 390 case UNW_X86_XMM3_lo: 391 case UNW_X86_XMM3_hi: 392 case UNW_X86_XMM4_lo: 393 case UNW_X86_XMM4_hi: 394 case UNW_X86_XMM5_lo: 395 case UNW_X86_XMM5_hi: 396 case UNW_X86_XMM6_lo: 397 case UNW_X86_XMM6_hi: 398 case UNW_X86_XMM7_lo: 399 case UNW_X86_XMM7_hi: 400 loc = x86_scratch_loc (c, reg); 401 break; 402 403 default: 404 Debug (1, "bad register number %u\n", reg); 405 return -UNW_EBADREG; 406 } 407 408 if (write) 409 return dwarf_putfp (&c->dwarf, loc, *valp); 410 else 411 return dwarf_getfp (&c->dwarf, loc, valp); 412} 413