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