Add docs and arch tests to BMI.
[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
5f6a2351 152alpha_mdebug_after_prologue (CORE_ADDR pc, struct mdebug_extra_func_info *proc_desc)
d2427a71
RH
153{
154 if (proc_desc)
155 {
156 /* If function is frameless, then we need to do it the hard way. I
157 strongly suspect that frameless always means prologueless... */
3a48e6ff 158 if (alpha_mdebug_frameless (proc_desc))
d2427a71
RH
159 return 0;
160 }
161
162 return alpha_after_prologue (pc);
163}
164
165/* Return non-zero if we *might* be in a function prologue. Return zero
166 if we are definitively *not* in a function prologue. */
167
168static int
5f6a2351 169alpha_mdebug_in_prologue (CORE_ADDR pc, struct mdebug_extra_func_info *proc_desc)
d2427a71
RH
170{
171 CORE_ADDR after_prologue_pc = alpha_mdebug_after_prologue (pc, proc_desc);
172 return (after_prologue_pc == 0 || pc < after_prologue_pc);
173}
174
175\f
176/* Frame unwinder that reads mdebug PDRs. */
177
178struct alpha_mdebug_unwind_cache
179{
5f6a2351 180 struct mdebug_extra_func_info *proc_desc;
d2427a71 181 CORE_ADDR vfp;
0cd9ab92 182 struct trad_frame_saved_reg *saved_regs;
d2427a71
RH
183};
184
185/* Extract all of the information about the frame from PROC_DESC
186 and store the resulting register save locations in the structure. */
187
188static struct alpha_mdebug_unwind_cache *
6834c9bb 189alpha_mdebug_frame_unwind_cache (struct frame_info *this_frame,
d2427a71
RH
190 void **this_prologue_cache)
191{
192 struct alpha_mdebug_unwind_cache *info;
5f6a2351 193 struct mdebug_extra_func_info *proc_desc;
d2427a71
RH
194 ULONGEST vfp;
195 CORE_ADDR pc, reg_position;
196 unsigned long mask;
197 int ireg, returnreg;
198
199 if (*this_prologue_cache)
200 return *this_prologue_cache;
201
202 info = FRAME_OBSTACK_ZALLOC (struct alpha_mdebug_unwind_cache);
203 *this_prologue_cache = info;
88828b32 204 pc = get_frame_address_in_block (this_frame);
d2427a71
RH
205
206 /* ??? We don't seem to be able to cache the lookup of the PDR
207 from alpha_mdebug_frame_p. It'd be nice if we could change
208 the arguments to that function. Oh well. */
209 proc_desc = find_proc_desc (pc);
210 info->proc_desc = proc_desc;
211 gdb_assert (proc_desc != NULL);
212
0cd9ab92 213 info->saved_regs = trad_frame_alloc_saved_regs (this_frame);
d2427a71
RH
214
215 /* The VFP of the frame is at FRAME_REG+FRAME_OFFSET. */
6834c9bb 216 vfp = get_frame_register_unsigned (this_frame, PROC_FRAME_REG (proc_desc));
d2427a71
RH
217 vfp += PROC_FRAME_OFFSET (info->proc_desc);
218 info->vfp = vfp;
219
220 /* Fill in the offsets for the registers which gen_mask says were saved. */
221
222 reg_position = vfp + PROC_REG_OFFSET (proc_desc);
223 mask = PROC_REG_MASK (proc_desc);
224 returnreg = PROC_PC_REG (proc_desc);
225
226 /* Note that RA is always saved first, regardless of its actual
227 register number. */
228 if (mask & (1 << returnreg))
229 {
230 /* Clear bit for RA so we don't save it again later. */
231 mask &= ~(1 << returnreg);
232
0cd9ab92 233 info->saved_regs[returnreg].addr = reg_position;
d2427a71
RH
234 reg_position += 8;
235 }
236
237 for (ireg = 0; ireg <= 31; ++ireg)
238 if (mask & (1 << ireg))
239 {
0cd9ab92 240 info->saved_regs[ireg].addr = reg_position;
d2427a71
RH
241 reg_position += 8;
242 }
243
244 reg_position = vfp + PROC_FREG_OFFSET (proc_desc);
245 mask = PROC_FREG_MASK (proc_desc);
246
247 for (ireg = 0; ireg <= 31; ++ireg)
248 if (mask & (1 << ireg))
249 {
0cd9ab92 250 info->saved_regs[ALPHA_FP0_REGNUM + ireg].addr = reg_position;
d2427a71
RH
251 reg_position += 8;
252 }
253
0cd9ab92
UW
254 /* The stack pointer of the previous frame is computed by popping
255 the current stack frame. */
256 if (!trad_frame_addr_p (info->saved_regs, ALPHA_SP_REGNUM))
257 trad_frame_set_value (info->saved_regs, ALPHA_SP_REGNUM, vfp);
258
d2427a71
RH
259 return info;
260}
261
262/* Given a GDB frame, determine the address of the calling function's
263 frame. This will be used to create a new GDB frame struct. */
264
265static void
6834c9bb 266alpha_mdebug_frame_this_id (struct frame_info *this_frame,
d2427a71
RH
267 void **this_prologue_cache,
268 struct frame_id *this_id)
269{
270 struct alpha_mdebug_unwind_cache *info
6834c9bb 271 = alpha_mdebug_frame_unwind_cache (this_frame, this_prologue_cache);
d2427a71 272
6834c9bb 273 *this_id = frame_id_build (info->vfp, get_frame_func (this_frame));
d2427a71
RH
274}
275
276/* Retrieve the value of REGNUM in FRAME. Don't give up! */
277
6834c9bb
JB
278static struct value *
279alpha_mdebug_frame_prev_register (struct frame_info *this_frame,
280 void **this_prologue_cache, int regnum)
d2427a71
RH
281{
282 struct alpha_mdebug_unwind_cache *info
6834c9bb 283 = alpha_mdebug_frame_unwind_cache (this_frame, this_prologue_cache);
d2427a71 284
d2427a71
RH
285 /* The PC of the previous frame is stored in the link register of
286 the current frame. Frob regnum so that we pull the value from
287 the correct place. */
087779b1 288 if (regnum == ALPHA_PC_REGNUM)
d2427a71
RH
289 regnum = PROC_PC_REG (info->proc_desc);
290
0cd9ab92 291 return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum);
d2427a71
RH
292}
293
3a48e6ff
JG
294/* Return a non-zero result if the size of the stack frame exceeds the
295 maximum debuggable frame size (512 Kbytes); zero otherwise. */
296
297static int
298alpha_mdebug_max_frame_size_exceeded (struct mdebug_extra_func_info *proc_desc)
299{
300 /* If frame offset is null, we can be in two cases: either the
301 function is frameless (the stack frame is null) or its
302 frame exceeds the maximum debuggable frame size (512 Kbytes). */
303
304 return (PROC_FRAME_OFFSET (proc_desc) == 0
305 && !alpha_mdebug_frameless (proc_desc));
306}
307
6834c9bb
JB
308static int
309alpha_mdebug_frame_sniffer (const struct frame_unwind *self,
310 struct frame_info *this_frame,
311 void **this_cache)
d2427a71 312{
6834c9bb 313 CORE_ADDR pc = get_frame_address_in_block (this_frame);
5f6a2351 314 struct mdebug_extra_func_info *proc_desc;
d2427a71
RH
315
316 /* If this PC does not map to a PDR, then clearly this isn't an
317 mdebug frame. */
318 proc_desc = find_proc_desc (pc);
319 if (proc_desc == NULL)
6834c9bb 320 return 0;
d2427a71 321
fbe586ae
RH
322 /* If we're in the prologue, the PDR for this frame is not yet valid.
323 Say no here and we'll fall back on the heuristic unwinder. */
324 if (alpha_mdebug_in_prologue (pc, proc_desc))
6834c9bb 325 return 0;
fbe586ae 326
3a48e6ff
JG
327 /* If the maximum debuggable frame size has been exceeded, the
328 proc desc is bogus. Fall back on the heuristic unwinder. */
329 if (alpha_mdebug_max_frame_size_exceeded (proc_desc))
330 return 0;
331
6834c9bb 332 return 1;
d2427a71
RH
333}
334
6834c9bb
JB
335static const struct frame_unwind alpha_mdebug_frame_unwind = {
336 NORMAL_FRAME,
337 alpha_mdebug_frame_this_id,
338 alpha_mdebug_frame_prev_register,
339 NULL,
340 alpha_mdebug_frame_sniffer
341};
342
d2427a71 343static CORE_ADDR
6834c9bb 344alpha_mdebug_frame_base_address (struct frame_info *this_frame,
d2427a71
RH
345 void **this_prologue_cache)
346{
347 struct alpha_mdebug_unwind_cache *info
6834c9bb 348 = alpha_mdebug_frame_unwind_cache (this_frame, this_prologue_cache);
d2427a71 349
fbe586ae 350 return info->vfp;
d2427a71
RH
351}
352
353static CORE_ADDR
6834c9bb 354alpha_mdebug_frame_locals_address (struct frame_info *this_frame,
d2427a71
RH
355 void **this_prologue_cache)
356{
357 struct alpha_mdebug_unwind_cache *info
6834c9bb 358 = alpha_mdebug_frame_unwind_cache (this_frame, this_prologue_cache);
d2427a71 359
fbe586ae 360 return info->vfp - PROC_LOCALOFF (info->proc_desc);
d2427a71
RH
361}
362
363static CORE_ADDR
6834c9bb 364alpha_mdebug_frame_args_address (struct frame_info *this_frame,
d2427a71
RH
365 void **this_prologue_cache)
366{
367 struct alpha_mdebug_unwind_cache *info
6834c9bb 368 = alpha_mdebug_frame_unwind_cache (this_frame, this_prologue_cache);
d2427a71 369
fbe586ae 370 return info->vfp - ALPHA_NUM_ARG_REGS * 8;
d2427a71
RH
371}
372
373static const struct frame_base alpha_mdebug_frame_base = {
374 &alpha_mdebug_frame_unwind,
375 alpha_mdebug_frame_base_address,
376 alpha_mdebug_frame_locals_address,
377 alpha_mdebug_frame_args_address
378};
379
380static const struct frame_base *
6834c9bb 381alpha_mdebug_frame_base_sniffer (struct frame_info *this_frame)
d2427a71 382{
6834c9bb 383 CORE_ADDR pc = get_frame_address_in_block (this_frame);
5f6a2351 384 struct mdebug_extra_func_info *proc_desc;
d2427a71
RH
385
386 /* If this PC does not map to a PDR, then clearly this isn't an
387 mdebug frame. */
388 proc_desc = find_proc_desc (pc);
389 if (proc_desc == NULL)
390 return NULL;
391
3a48e6ff
JG
392 /* If the maximum debuggable frame size has been exceeded, the
393 proc desc is bogus. Fall back on the heuristic unwinder. */
394 if (alpha_mdebug_max_frame_size_exceeded (proc_desc))
395 return 0;
396
d2427a71
RH
397 return &alpha_mdebug_frame_base;
398}
399
400\f
401void
402alpha_mdebug_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
403{
404 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
405
6834c9bb 406 frame_unwind_append_unwinder (gdbarch, &alpha_mdebug_frame_unwind);
336d1bba 407 frame_base_append_sniffer (gdbarch, alpha_mdebug_frame_base_sniffer);
d2427a71 408}
This page took 0.465757 seconds and 4 git commands to generate.