2011-01-07 Michael Snyder <msnyder@vmware.com>
[deliverable/binutils-gdb.git] / gdb / alpha-mdebug-tdep.c
CommitLineData
d2427a71 1/* Target-dependent mdebug code for the ALPHA architecture.
6aba47ca 2 Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
7b6bb8da 3 2003, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
d2427a71
RH
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
a9762ec7 9 the Free Software Foundation; either version 3 of the License, or
d2427a71
RH
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
a9762ec7 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
d2427a71
RH
19
20#include "defs.h"
21#include "frame.h"
22#include "frame-unwind.h"
23#include "frame-base.h"
d2427a71 24#include "symtab.h"
d2427a71 25#include "gdbcore.h"
d2427a71
RH
26#include "block.h"
27#include "gdb_assert.h"
62f6180c 28#include "gdb_string.h"
0cd9ab92 29#include "trad-frame.h"
d2427a71 30
d2427a71 31#include "alpha-tdep.h"
5f6a2351 32#include "mdebugread.h"
d2427a71
RH
33
34/* FIXME: Some of this code should perhaps be merged with mips. */
35
36/* *INDENT-OFF* */
37/* Layout of a stack frame on the alpha:
38
39 | |
40 pdr members: | 7th ... nth arg, |
41 | `pushed' by caller. |
42 | |
43----------------|-------------------------------|<-- old_sp == vfp
44 ^ ^ ^ ^ | |
45 | | | | | |
46 | |localoff | Copies of 1st .. 6th |
47 | | | | | argument if necessary. |
48 | | | v | |
42efa47a 49 | | | --- |-------------------------------|<-- LOCALS_ADDRESS
d2427a71
RH
50 | | | | |
51 | | | | Locals and temporaries. |
52 | | | | |
53 | | | |-------------------------------|
54 | | | | |
55 |-fregoffset | Saved float registers. |
56 | | | | F9 |
57 | | | | . |
58 | | | | . |
59 | | | | F2 |
60 | | v | |
61 | | -------|-------------------------------|
62 | | | |
63 | | | Saved registers. |
64 | | | S6 |
65 |-regoffset | . |
66 | | | . |
67 | | | S0 |
68 | | | pdr.pcreg |
69 | v | |
70 | ----------|-------------------------------|
71 | | |
72 frameoffset | Argument build area, gets |
73 | | 7th ... nth arg for any |
74 | | called procedure. |
75 v | |
76 -------------|-------------------------------|<-- sp
77 | |
78*/
79/* *INDENT-ON* */
80
81#define PROC_LOW_ADDR(proc) ((proc)->pdr.adr)
82#define PROC_FRAME_OFFSET(proc) ((proc)->pdr.frameoffset)
83#define PROC_FRAME_REG(proc) ((proc)->pdr.framereg)
84#define PROC_REG_MASK(proc) ((proc)->pdr.regmask)
85#define PROC_FREG_MASK(proc) ((proc)->pdr.fregmask)
86#define PROC_REG_OFFSET(proc) ((proc)->pdr.regoffset)
87#define PROC_FREG_OFFSET(proc) ((proc)->pdr.fregoffset)
88#define PROC_PC_REG(proc) ((proc)->pdr.pcreg)
89#define PROC_LOCALOFF(proc) ((proc)->pdr.localoff)
90\f
91/* Locate the mdebug PDR for the given PC. Return null if one can't
92 be found; you'll have to fall back to other methods in that case. */
93
5f6a2351 94static struct mdebug_extra_func_info *
d2427a71
RH
95find_proc_desc (CORE_ADDR pc)
96{
97 struct block *b = block_for_pc (pc);
5f6a2351 98 struct mdebug_extra_func_info *proc_desc = NULL;
d2427a71 99 struct symbol *sym = NULL;
62f6180c 100 char *sh_name = NULL;
d2427a71
RH
101
102 if (b)
103 {
104 CORE_ADDR startaddr;
62f6180c 105 find_pc_partial_function (pc, &sh_name, &startaddr, NULL);
d2427a71
RH
106
107 if (startaddr > BLOCK_START (b))
108 /* This is the "pathological" case referred to in a comment in
109 print_frame_info. It might be better to move this check into
110 symbol reading. */
111 sym = NULL;
112 else
2570f2b7 113 sym = lookup_symbol (MDEBUG_EFI_SYMBOL_NAME, b, LABEL_DOMAIN, 0);
d2427a71
RH
114 }
115
116 if (sym)
117 {
37049e31 118 proc_desc = (struct mdebug_extra_func_info *) SYMBOL_VALUE_BYTES (sym);
d2427a71 119
62f6180c
UW
120 /* Correct incorrect setjmp procedure descriptor from the library
121 to make backtrace through setjmp work. */
122 if (proc_desc->pdr.pcreg == 0
123 && strcmp (sh_name, "setjmp") == 0)
124 {
125 proc_desc->pdr.pcreg = ALPHA_RA_REGNUM;
126 proc_desc->pdr.regmask = 0x80000000;
127 proc_desc->pdr.regoffset = -4;
128 }
129
d2427a71
RH
130 /* If we never found a PDR for this function in symbol reading,
131 then examine prologues to find the information. */
132 if (proc_desc->pdr.framereg == -1)
133 proc_desc = NULL;
134 }
135
136 return proc_desc;
137}
138
3a48e6ff
JG
139/* Return a non-zero result if the function is frameless; zero otherwise. */
140
141static int
142alpha_mdebug_frameless (struct mdebug_extra_func_info *proc_desc)
143{
144 return (PROC_FRAME_REG (proc_desc) == ALPHA_SP_REGNUM
145 && PROC_FRAME_OFFSET (proc_desc) == 0);
146}
147
d2427a71
RH
148/* This returns the PC of the first inst after the prologue. If we can't
149 find the prologue, then return 0. */
150
151static CORE_ADDR
0963b4bd
MS
152alpha_mdebug_after_prologue (CORE_ADDR pc,
153 struct mdebug_extra_func_info *proc_desc)
d2427a71
RH
154{
155 if (proc_desc)
156 {
157 /* If function is frameless, then we need to do it the hard way. I
0963b4bd 158 strongly suspect that frameless always means prologueless... */
3a48e6ff 159 if (alpha_mdebug_frameless (proc_desc))
d2427a71
RH
160 return 0;
161 }
162
163 return alpha_after_prologue (pc);
164}
165
166/* Return non-zero if we *might* be in a function prologue. Return zero
167 if we are definitively *not* in a function prologue. */
168
169static int
0963b4bd
MS
170alpha_mdebug_in_prologue (CORE_ADDR pc,
171 struct mdebug_extra_func_info *proc_desc)
d2427a71
RH
172{
173 CORE_ADDR after_prologue_pc = alpha_mdebug_after_prologue (pc, proc_desc);
174 return (after_prologue_pc == 0 || pc < after_prologue_pc);
175}
176
177\f
178/* Frame unwinder that reads mdebug PDRs. */
179
180struct alpha_mdebug_unwind_cache
181{
5f6a2351 182 struct mdebug_extra_func_info *proc_desc;
d2427a71 183 CORE_ADDR vfp;
0cd9ab92 184 struct trad_frame_saved_reg *saved_regs;
d2427a71
RH
185};
186
187/* Extract all of the information about the frame from PROC_DESC
188 and store the resulting register save locations in the structure. */
189
190static struct alpha_mdebug_unwind_cache *
6834c9bb 191alpha_mdebug_frame_unwind_cache (struct frame_info *this_frame,
d2427a71
RH
192 void **this_prologue_cache)
193{
194 struct alpha_mdebug_unwind_cache *info;
5f6a2351 195 struct mdebug_extra_func_info *proc_desc;
d2427a71
RH
196 ULONGEST vfp;
197 CORE_ADDR pc, reg_position;
198 unsigned long mask;
199 int ireg, returnreg;
200
201 if (*this_prologue_cache)
202 return *this_prologue_cache;
203
204 info = FRAME_OBSTACK_ZALLOC (struct alpha_mdebug_unwind_cache);
205 *this_prologue_cache = info;
88828b32 206 pc = get_frame_address_in_block (this_frame);
d2427a71
RH
207
208 /* ??? We don't seem to be able to cache the lookup of the PDR
209 from alpha_mdebug_frame_p. It'd be nice if we could change
210 the arguments to that function. Oh well. */
211 proc_desc = find_proc_desc (pc);
212 info->proc_desc = proc_desc;
213 gdb_assert (proc_desc != NULL);
214
0cd9ab92 215 info->saved_regs = trad_frame_alloc_saved_regs (this_frame);
d2427a71
RH
216
217 /* The VFP of the frame is at FRAME_REG+FRAME_OFFSET. */
6834c9bb 218 vfp = get_frame_register_unsigned (this_frame, PROC_FRAME_REG (proc_desc));
d2427a71
RH
219 vfp += PROC_FRAME_OFFSET (info->proc_desc);
220 info->vfp = vfp;
221
222 /* Fill in the offsets for the registers which gen_mask says were saved. */
223
224 reg_position = vfp + PROC_REG_OFFSET (proc_desc);
225 mask = PROC_REG_MASK (proc_desc);
226 returnreg = PROC_PC_REG (proc_desc);
227
228 /* Note that RA is always saved first, regardless of its actual
229 register number. */
230 if (mask & (1 << returnreg))
231 {
0963b4bd 232 /* Clear bit for RA so we don't save it again later. */
d2427a71
RH
233 mask &= ~(1 << returnreg);
234
0cd9ab92 235 info->saved_regs[returnreg].addr = reg_position;
d2427a71
RH
236 reg_position += 8;
237 }
238
239 for (ireg = 0; ireg <= 31; ++ireg)
240 if (mask & (1 << ireg))
241 {
0cd9ab92 242 info->saved_regs[ireg].addr = reg_position;
d2427a71
RH
243 reg_position += 8;
244 }
245
246 reg_position = vfp + PROC_FREG_OFFSET (proc_desc);
247 mask = PROC_FREG_MASK (proc_desc);
248
249 for (ireg = 0; ireg <= 31; ++ireg)
250 if (mask & (1 << ireg))
251 {
0cd9ab92 252 info->saved_regs[ALPHA_FP0_REGNUM + ireg].addr = reg_position;
d2427a71
RH
253 reg_position += 8;
254 }
255
0cd9ab92
UW
256 /* The stack pointer of the previous frame is computed by popping
257 the current stack frame. */
258 if (!trad_frame_addr_p (info->saved_regs, ALPHA_SP_REGNUM))
259 trad_frame_set_value (info->saved_regs, ALPHA_SP_REGNUM, vfp);
260
d2427a71
RH
261 return info;
262}
263
264/* Given a GDB frame, determine the address of the calling function's
265 frame. This will be used to create a new GDB frame struct. */
266
267static void
6834c9bb 268alpha_mdebug_frame_this_id (struct frame_info *this_frame,
d2427a71
RH
269 void **this_prologue_cache,
270 struct frame_id *this_id)
271{
272 struct alpha_mdebug_unwind_cache *info
6834c9bb 273 = alpha_mdebug_frame_unwind_cache (this_frame, this_prologue_cache);
d2427a71 274
6834c9bb 275 *this_id = frame_id_build (info->vfp, get_frame_func (this_frame));
d2427a71
RH
276}
277
278/* Retrieve the value of REGNUM in FRAME. Don't give up! */
279
6834c9bb
JB
280static struct value *
281alpha_mdebug_frame_prev_register (struct frame_info *this_frame,
282 void **this_prologue_cache, int regnum)
d2427a71
RH
283{
284 struct alpha_mdebug_unwind_cache *info
6834c9bb 285 = alpha_mdebug_frame_unwind_cache (this_frame, this_prologue_cache);
d2427a71 286
d2427a71
RH
287 /* The PC of the previous frame is stored in the link register of
288 the current frame. Frob regnum so that we pull the value from
289 the correct place. */
087779b1 290 if (regnum == ALPHA_PC_REGNUM)
d2427a71
RH
291 regnum = PROC_PC_REG (info->proc_desc);
292
0cd9ab92 293 return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum);
d2427a71
RH
294}
295
3a48e6ff
JG
296/* Return a non-zero result if the size of the stack frame exceeds the
297 maximum debuggable frame size (512 Kbytes); zero otherwise. */
298
299static int
300alpha_mdebug_max_frame_size_exceeded (struct mdebug_extra_func_info *proc_desc)
301{
302 /* If frame offset is null, we can be in two cases: either the
303 function is frameless (the stack frame is null) or its
304 frame exceeds the maximum debuggable frame size (512 Kbytes). */
305
306 return (PROC_FRAME_OFFSET (proc_desc) == 0
307 && !alpha_mdebug_frameless (proc_desc));
308}
309
6834c9bb
JB
310static int
311alpha_mdebug_frame_sniffer (const struct frame_unwind *self,
312 struct frame_info *this_frame,
313 void **this_cache)
d2427a71 314{
6834c9bb 315 CORE_ADDR pc = get_frame_address_in_block (this_frame);
5f6a2351 316 struct mdebug_extra_func_info *proc_desc;
d2427a71
RH
317
318 /* If this PC does not map to a PDR, then clearly this isn't an
319 mdebug frame. */
320 proc_desc = find_proc_desc (pc);
321 if (proc_desc == NULL)
6834c9bb 322 return 0;
d2427a71 323
fbe586ae
RH
324 /* If we're in the prologue, the PDR for this frame is not yet valid.
325 Say no here and we'll fall back on the heuristic unwinder. */
326 if (alpha_mdebug_in_prologue (pc, proc_desc))
6834c9bb 327 return 0;
fbe586ae 328
3a48e6ff
JG
329 /* If the maximum debuggable frame size has been exceeded, the
330 proc desc is bogus. Fall back on the heuristic unwinder. */
331 if (alpha_mdebug_max_frame_size_exceeded (proc_desc))
332 return 0;
333
6834c9bb 334 return 1;
d2427a71
RH
335}
336
6834c9bb
JB
337static const struct frame_unwind alpha_mdebug_frame_unwind = {
338 NORMAL_FRAME,
339 alpha_mdebug_frame_this_id,
340 alpha_mdebug_frame_prev_register,
341 NULL,
342 alpha_mdebug_frame_sniffer
343};
344
d2427a71 345static CORE_ADDR
6834c9bb 346alpha_mdebug_frame_base_address (struct frame_info *this_frame,
d2427a71
RH
347 void **this_prologue_cache)
348{
349 struct alpha_mdebug_unwind_cache *info
6834c9bb 350 = alpha_mdebug_frame_unwind_cache (this_frame, this_prologue_cache);
d2427a71 351
fbe586ae 352 return info->vfp;
d2427a71
RH
353}
354
355static CORE_ADDR
6834c9bb 356alpha_mdebug_frame_locals_address (struct frame_info *this_frame,
d2427a71
RH
357 void **this_prologue_cache)
358{
359 struct alpha_mdebug_unwind_cache *info
6834c9bb 360 = alpha_mdebug_frame_unwind_cache (this_frame, this_prologue_cache);
d2427a71 361
fbe586ae 362 return info->vfp - PROC_LOCALOFF (info->proc_desc);
d2427a71
RH
363}
364
365static CORE_ADDR
6834c9bb 366alpha_mdebug_frame_args_address (struct frame_info *this_frame,
d2427a71
RH
367 void **this_prologue_cache)
368{
369 struct alpha_mdebug_unwind_cache *info
6834c9bb 370 = alpha_mdebug_frame_unwind_cache (this_frame, this_prologue_cache);
d2427a71 371
fbe586ae 372 return info->vfp - ALPHA_NUM_ARG_REGS * 8;
d2427a71
RH
373}
374
375static const struct frame_base alpha_mdebug_frame_base = {
376 &alpha_mdebug_frame_unwind,
377 alpha_mdebug_frame_base_address,
378 alpha_mdebug_frame_locals_address,
379 alpha_mdebug_frame_args_address
380};
381
382static const struct frame_base *
6834c9bb 383alpha_mdebug_frame_base_sniffer (struct frame_info *this_frame)
d2427a71 384{
6834c9bb 385 CORE_ADDR pc = get_frame_address_in_block (this_frame);
5f6a2351 386 struct mdebug_extra_func_info *proc_desc;
d2427a71
RH
387
388 /* If this PC does not map to a PDR, then clearly this isn't an
389 mdebug frame. */
390 proc_desc = find_proc_desc (pc);
391 if (proc_desc == NULL)
392 return NULL;
393
3a48e6ff
JG
394 /* If the maximum debuggable frame size has been exceeded, the
395 proc desc is bogus. Fall back on the heuristic unwinder. */
396 if (alpha_mdebug_max_frame_size_exceeded (proc_desc))
397 return 0;
398
d2427a71
RH
399 return &alpha_mdebug_frame_base;
400}
401
402\f
403void
404alpha_mdebug_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
405{
406 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
407
6834c9bb 408 frame_unwind_append_unwinder (gdbarch, &alpha_mdebug_frame_unwind);
336d1bba 409 frame_base_append_sniffer (gdbarch, alpha_mdebug_frame_base_sniffer);
d2427a71 410}
This page took 0.472782 seconds and 4 git commands to generate.