1130803Smarcel/* Target-dependent mdebug code for the ALPHA architecture.
2130803Smarcel   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
3130803Smarcel   Free Software Foundation, Inc.
4130803Smarcel
5130803Smarcel   This file is part of GDB.
6130803Smarcel
7130803Smarcel   This program is free software; you can redistribute it and/or modify
8130803Smarcel   it under the terms of the GNU General Public License as published by
9130803Smarcel   the Free Software Foundation; either version 2 of the License, or
10130803Smarcel   (at your option) any later version.
11130803Smarcel
12130803Smarcel   This program is distributed in the hope that it will be useful,
13130803Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
14130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15130803Smarcel   GNU General Public License for more details.
16130803Smarcel
17130803Smarcel   You should have received a copy of the GNU General Public License
18130803Smarcel   along with this program; if not, write to the Free Software
19130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
20130803Smarcel   Boston, MA 02111-1307, USA.  */
21130803Smarcel
22130803Smarcel#include "defs.h"
23130803Smarcel#include "frame.h"
24130803Smarcel#include "frame-unwind.h"
25130803Smarcel#include "frame-base.h"
26130803Smarcel#include "symtab.h"
27130803Smarcel#include "gdbcore.h"
28130803Smarcel#include "block.h"
29130803Smarcel#include "gdb_assert.h"
30130803Smarcel
31130803Smarcel#include "alpha-tdep.h"
32130803Smarcel
33130803Smarcel/* FIXME: Some of this code should perhaps be merged with mips.  */
34130803Smarcel
35130803Smarcel/* *INDENT-OFF* */
36130803Smarcel/* Layout of a stack frame on the alpha:
37130803Smarcel
38130803Smarcel                |				|
39130803Smarcel pdr members:	|  7th ... nth arg,		|
40130803Smarcel                |  `pushed' by caller.		|
41130803Smarcel                |				|
42130803Smarcel----------------|-------------------------------|<--  old_sp == vfp
43130803Smarcel   ^  ^  ^  ^	|				|
44130803Smarcel   |  |  |  |	|				|
45130803Smarcel   |  |localoff	|  Copies of 1st .. 6th		|
46130803Smarcel   |  |  |  |	|  argument if necessary.	|
47130803Smarcel   |  |  |  v	|				|
48130803Smarcel   |  |  |  ---	|-------------------------------|<-- LOCALS_ADDRESS
49130803Smarcel   |  |  |      |				|
50130803Smarcel   |  |  |      |  Locals and temporaries.	|
51130803Smarcel   |  |  |      |				|
52130803Smarcel   |  |  |      |-------------------------------|
53130803Smarcel   |  |  |      |				|
54130803Smarcel   |-fregoffset	|  Saved float registers.	|
55130803Smarcel   |  |  |      |  F9				|
56130803Smarcel   |  |  |      |   .				|
57130803Smarcel   |  |  |      |   .				|
58130803Smarcel   |  |  |      |  F2				|
59130803Smarcel   |  |  v      |				|
60130803Smarcel   |  |  -------|-------------------------------|
61130803Smarcel   |  |         |				|
62130803Smarcel   |  |         |  Saved registers.		|
63130803Smarcel   |  |         |  S6				|
64130803Smarcel   |-regoffset	|   .				|
65130803Smarcel   |  |         |   .				|
66130803Smarcel   |  |         |  S0				|
67130803Smarcel   |  |         |  pdr.pcreg			|
68130803Smarcel   |  v         |				|
69130803Smarcel   |  ----------|-------------------------------|
70130803Smarcel   |            |				|
71130803Smarcel frameoffset    |  Argument build area, gets	|
72130803Smarcel   |            |  7th ... nth arg for any	|
73130803Smarcel   |            |  called procedure.		|
74130803Smarcel   v            |  				|
75130803Smarcel   -------------|-------------------------------|<-- sp
76130803Smarcel                |				|
77130803Smarcel*/
78130803Smarcel/* *INDENT-ON* */
79130803Smarcel
80130803Smarcel#define PROC_LOW_ADDR(proc) ((proc)->pdr.adr)
81130803Smarcel#define PROC_FRAME_OFFSET(proc) ((proc)->pdr.frameoffset)
82130803Smarcel#define PROC_FRAME_REG(proc) ((proc)->pdr.framereg)
83130803Smarcel#define PROC_REG_MASK(proc) ((proc)->pdr.regmask)
84130803Smarcel#define PROC_FREG_MASK(proc) ((proc)->pdr.fregmask)
85130803Smarcel#define PROC_REG_OFFSET(proc) ((proc)->pdr.regoffset)
86130803Smarcel#define PROC_FREG_OFFSET(proc) ((proc)->pdr.fregoffset)
87130803Smarcel#define PROC_PC_REG(proc) ((proc)->pdr.pcreg)
88130803Smarcel#define PROC_LOCALOFF(proc) ((proc)->pdr.localoff)
89130803Smarcel
90130803Smarcel/* Locate the mdebug PDR for the given PC.  Return null if one can't
91130803Smarcel   be found; you'll have to fall back to other methods in that case.  */
92130803Smarcel
93130803Smarcelstatic alpha_extra_func_info_t
94130803Smarcelfind_proc_desc (CORE_ADDR pc)
95130803Smarcel{
96130803Smarcel  struct block *b = block_for_pc (pc);
97130803Smarcel  alpha_extra_func_info_t proc_desc = NULL;
98130803Smarcel  struct symbol *sym = NULL;
99130803Smarcel
100130803Smarcel  if (b)
101130803Smarcel    {
102130803Smarcel      CORE_ADDR startaddr;
103130803Smarcel      find_pc_partial_function (pc, NULL, &startaddr, NULL);
104130803Smarcel
105130803Smarcel      if (startaddr > BLOCK_START (b))
106130803Smarcel	/* This is the "pathological" case referred to in a comment in
107130803Smarcel	   print_frame_info.  It might be better to move this check into
108130803Smarcel	   symbol reading.  */
109130803Smarcel	sym = NULL;
110130803Smarcel      else
111130803Smarcel	sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_DOMAIN, 0, NULL);
112130803Smarcel    }
113130803Smarcel
114130803Smarcel  if (sym)
115130803Smarcel    {
116130803Smarcel      proc_desc = (alpha_extra_func_info_t) SYMBOL_VALUE (sym);
117130803Smarcel
118130803Smarcel      /* If we never found a PDR for this function in symbol reading,
119130803Smarcel	 then examine prologues to find the information.  */
120130803Smarcel      if (proc_desc->pdr.framereg == -1)
121130803Smarcel	proc_desc = NULL;
122130803Smarcel    }
123130803Smarcel
124130803Smarcel  return proc_desc;
125130803Smarcel}
126130803Smarcel
127130803Smarcel/* This returns the PC of the first inst after the prologue.  If we can't
128130803Smarcel   find the prologue, then return 0.  */
129130803Smarcel
130130803Smarcelstatic CORE_ADDR
131130803Smarcelalpha_mdebug_after_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc)
132130803Smarcel{
133130803Smarcel  if (proc_desc)
134130803Smarcel    {
135130803Smarcel      /* If function is frameless, then we need to do it the hard way.  I
136130803Smarcel         strongly suspect that frameless always means prologueless... */
137130803Smarcel      if (PROC_FRAME_REG (proc_desc) == ALPHA_SP_REGNUM
138130803Smarcel	  && PROC_FRAME_OFFSET (proc_desc) == 0)
139130803Smarcel	return 0;
140130803Smarcel    }
141130803Smarcel
142130803Smarcel  return alpha_after_prologue (pc);
143130803Smarcel}
144130803Smarcel
145130803Smarcel/* Return non-zero if we *might* be in a function prologue.  Return zero
146130803Smarcel   if we are definitively *not* in a function prologue.  */
147130803Smarcel
148130803Smarcelstatic int
149130803Smarcelalpha_mdebug_in_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc)
150130803Smarcel{
151130803Smarcel  CORE_ADDR after_prologue_pc = alpha_mdebug_after_prologue (pc, proc_desc);
152130803Smarcel  return (after_prologue_pc == 0 || pc < after_prologue_pc);
153130803Smarcel}
154130803Smarcel
155130803Smarcel
156130803Smarcel/* Frame unwinder that reads mdebug PDRs.  */
157130803Smarcel
158130803Smarcelstruct alpha_mdebug_unwind_cache
159130803Smarcel{
160130803Smarcel  alpha_extra_func_info_t proc_desc;
161130803Smarcel  CORE_ADDR vfp;
162130803Smarcel  CORE_ADDR *saved_regs;
163130803Smarcel};
164130803Smarcel
165130803Smarcel/* Extract all of the information about the frame from PROC_DESC
166130803Smarcel   and store the resulting register save locations in the structure.  */
167130803Smarcel
168130803Smarcelstatic struct alpha_mdebug_unwind_cache *
169130803Smarcelalpha_mdebug_frame_unwind_cache (struct frame_info *next_frame,
170130803Smarcel				 void **this_prologue_cache)
171130803Smarcel{
172130803Smarcel  struct alpha_mdebug_unwind_cache *info;
173130803Smarcel  alpha_extra_func_info_t proc_desc;
174130803Smarcel  ULONGEST vfp;
175130803Smarcel  CORE_ADDR pc, reg_position;
176130803Smarcel  unsigned long mask;
177130803Smarcel  int ireg, returnreg;
178130803Smarcel
179130803Smarcel  if (*this_prologue_cache)
180130803Smarcel    return *this_prologue_cache;
181130803Smarcel
182130803Smarcel  info = FRAME_OBSTACK_ZALLOC (struct alpha_mdebug_unwind_cache);
183130803Smarcel  *this_prologue_cache = info;
184130803Smarcel  pc = frame_pc_unwind (next_frame);
185130803Smarcel
186130803Smarcel  /* ??? We don't seem to be able to cache the lookup of the PDR
187130803Smarcel     from alpha_mdebug_frame_p.  It'd be nice if we could change
188130803Smarcel     the arguments to that function.  Oh well.  */
189130803Smarcel  proc_desc = find_proc_desc (pc);
190130803Smarcel  info->proc_desc = proc_desc;
191130803Smarcel  gdb_assert (proc_desc != NULL);
192130803Smarcel
193130803Smarcel  info->saved_regs = frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS);
194130803Smarcel
195130803Smarcel  /* The VFP of the frame is at FRAME_REG+FRAME_OFFSET.  */
196130803Smarcel  frame_unwind_unsigned_register (next_frame, PROC_FRAME_REG (proc_desc), &vfp);
197130803Smarcel  vfp += PROC_FRAME_OFFSET (info->proc_desc);
198130803Smarcel  info->vfp = vfp;
199130803Smarcel
200130803Smarcel  /* Fill in the offsets for the registers which gen_mask says were saved.  */
201130803Smarcel
202130803Smarcel  reg_position = vfp + PROC_REG_OFFSET (proc_desc);
203130803Smarcel  mask = PROC_REG_MASK (proc_desc);
204130803Smarcel  returnreg = PROC_PC_REG (proc_desc);
205130803Smarcel
206130803Smarcel  /* Note that RA is always saved first, regardless of its actual
207130803Smarcel     register number.  */
208130803Smarcel  if (mask & (1 << returnreg))
209130803Smarcel    {
210130803Smarcel      /* Clear bit for RA so we don't save it again later. */
211130803Smarcel      mask &= ~(1 << returnreg);
212130803Smarcel
213130803Smarcel      info->saved_regs[returnreg] = reg_position;
214130803Smarcel      reg_position += 8;
215130803Smarcel    }
216130803Smarcel
217130803Smarcel  for (ireg = 0; ireg <= 31; ++ireg)
218130803Smarcel    if (mask & (1 << ireg))
219130803Smarcel      {
220130803Smarcel	info->saved_regs[ireg] = reg_position;
221130803Smarcel	reg_position += 8;
222130803Smarcel      }
223130803Smarcel
224130803Smarcel  reg_position = vfp + PROC_FREG_OFFSET (proc_desc);
225130803Smarcel  mask = PROC_FREG_MASK (proc_desc);
226130803Smarcel
227130803Smarcel  for (ireg = 0; ireg <= 31; ++ireg)
228130803Smarcel    if (mask & (1 << ireg))
229130803Smarcel      {
230130803Smarcel	info->saved_regs[ALPHA_FP0_REGNUM + ireg] = reg_position;
231130803Smarcel	reg_position += 8;
232130803Smarcel      }
233130803Smarcel
234130803Smarcel  return info;
235130803Smarcel}
236130803Smarcel
237130803Smarcel/* Given a GDB frame, determine the address of the calling function's
238130803Smarcel   frame.  This will be used to create a new GDB frame struct.  */
239130803Smarcel
240130803Smarcelstatic void
241130803Smarcelalpha_mdebug_frame_this_id (struct frame_info *next_frame,
242130803Smarcel			    void **this_prologue_cache,
243130803Smarcel			    struct frame_id *this_id)
244130803Smarcel{
245130803Smarcel  struct alpha_mdebug_unwind_cache *info
246130803Smarcel    = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
247130803Smarcel
248130803Smarcel  *this_id = frame_id_build (info->vfp, frame_func_unwind (next_frame));
249130803Smarcel}
250130803Smarcel
251130803Smarcel/* Retrieve the value of REGNUM in FRAME.  Don't give up!  */
252130803Smarcel
253130803Smarcelstatic void
254130803Smarcelalpha_mdebug_frame_prev_register (struct frame_info *next_frame,
255130803Smarcel				  void **this_prologue_cache,
256130803Smarcel				  int regnum, int *optimizedp,
257130803Smarcel				  enum lval_type *lvalp, CORE_ADDR *addrp,
258130803Smarcel				  int *realnump, void *bufferp)
259130803Smarcel{
260130803Smarcel  struct alpha_mdebug_unwind_cache *info
261130803Smarcel    = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
262130803Smarcel
263130803Smarcel  /* The PC of the previous frame is stored in the link register of
264130803Smarcel     the current frame.  Frob regnum so that we pull the value from
265130803Smarcel     the correct place.  */
266130803Smarcel  if (regnum == ALPHA_PC_REGNUM)
267130803Smarcel    regnum = PROC_PC_REG (info->proc_desc);
268130803Smarcel
269130803Smarcel  /* For all registers known to be saved in the current frame,
270130803Smarcel     do the obvious and pull the value out.  */
271130803Smarcel  if (info->saved_regs[regnum])
272130803Smarcel    {
273130803Smarcel      *optimizedp = 0;
274130803Smarcel      *lvalp = lval_memory;
275130803Smarcel      *addrp = info->saved_regs[regnum];
276130803Smarcel      *realnump = -1;
277130803Smarcel      if (bufferp != NULL)
278130803Smarcel	get_frame_memory (next_frame, *addrp, bufferp, ALPHA_REGISTER_SIZE);
279130803Smarcel      return;
280130803Smarcel    }
281130803Smarcel
282130803Smarcel  /* The stack pointer of the previous frame is computed by popping
283130803Smarcel     the current stack frame.  */
284130803Smarcel  if (regnum == ALPHA_SP_REGNUM)
285130803Smarcel    {
286130803Smarcel      *optimizedp = 0;
287130803Smarcel      *lvalp = not_lval;
288130803Smarcel      *addrp = 0;
289130803Smarcel      *realnump = -1;
290130803Smarcel      if (bufferp != NULL)
291130803Smarcel	store_unsigned_integer (bufferp, ALPHA_REGISTER_SIZE, info->vfp);
292130803Smarcel      return;
293130803Smarcel    }
294130803Smarcel
295130803Smarcel  /* Otherwise assume the next frame has the same register value.  */
296130803Smarcel  frame_register (next_frame, regnum, optimizedp, lvalp, addrp,
297130803Smarcel  		  realnump, bufferp);
298130803Smarcel}
299130803Smarcel
300130803Smarcelstatic const struct frame_unwind alpha_mdebug_frame_unwind = {
301130803Smarcel  NORMAL_FRAME,
302130803Smarcel  alpha_mdebug_frame_this_id,
303130803Smarcel  alpha_mdebug_frame_prev_register
304130803Smarcel};
305130803Smarcel
306130803Smarcelconst struct frame_unwind *
307130803Smarcelalpha_mdebug_frame_sniffer (struct frame_info *next_frame)
308130803Smarcel{
309130803Smarcel  CORE_ADDR pc = frame_pc_unwind (next_frame);
310130803Smarcel  alpha_extra_func_info_t proc_desc;
311130803Smarcel
312130803Smarcel  /* If this PC does not map to a PDR, then clearly this isn't an
313130803Smarcel     mdebug frame.  */
314130803Smarcel  proc_desc = find_proc_desc (pc);
315130803Smarcel  if (proc_desc == NULL)
316130803Smarcel    return NULL;
317130803Smarcel
318130803Smarcel  /* If we're in the prologue, the PDR for this frame is not yet valid.
319130803Smarcel     Say no here and we'll fall back on the heuristic unwinder.  */
320130803Smarcel  if (alpha_mdebug_in_prologue (pc, proc_desc))
321130803Smarcel    return NULL;
322130803Smarcel
323130803Smarcel  return &alpha_mdebug_frame_unwind;
324130803Smarcel}
325130803Smarcel
326130803Smarcelstatic CORE_ADDR
327130803Smarcelalpha_mdebug_frame_base_address (struct frame_info *next_frame,
328130803Smarcel				 void **this_prologue_cache)
329130803Smarcel{
330130803Smarcel  struct alpha_mdebug_unwind_cache *info
331130803Smarcel    = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
332130803Smarcel
333130803Smarcel  return info->vfp;
334130803Smarcel}
335130803Smarcel
336130803Smarcelstatic CORE_ADDR
337130803Smarcelalpha_mdebug_frame_locals_address (struct frame_info *next_frame,
338130803Smarcel				   void **this_prologue_cache)
339130803Smarcel{
340130803Smarcel  struct alpha_mdebug_unwind_cache *info
341130803Smarcel    = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
342130803Smarcel
343130803Smarcel  return info->vfp - PROC_LOCALOFF (info->proc_desc);
344130803Smarcel}
345130803Smarcel
346130803Smarcelstatic CORE_ADDR
347130803Smarcelalpha_mdebug_frame_args_address (struct frame_info *next_frame,
348130803Smarcel				 void **this_prologue_cache)
349130803Smarcel{
350130803Smarcel  struct alpha_mdebug_unwind_cache *info
351130803Smarcel    = alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
352130803Smarcel
353130803Smarcel  return info->vfp - ALPHA_NUM_ARG_REGS * 8;
354130803Smarcel}
355130803Smarcel
356130803Smarcelstatic const struct frame_base alpha_mdebug_frame_base = {
357130803Smarcel  &alpha_mdebug_frame_unwind,
358130803Smarcel  alpha_mdebug_frame_base_address,
359130803Smarcel  alpha_mdebug_frame_locals_address,
360130803Smarcel  alpha_mdebug_frame_args_address
361130803Smarcel};
362130803Smarcel
363130803Smarcelstatic const struct frame_base *
364130803Smarcelalpha_mdebug_frame_base_sniffer (struct frame_info *next_frame)
365130803Smarcel{
366130803Smarcel  CORE_ADDR pc = frame_pc_unwind (next_frame);
367130803Smarcel  alpha_extra_func_info_t proc_desc;
368130803Smarcel
369130803Smarcel  /* If this PC does not map to a PDR, then clearly this isn't an
370130803Smarcel     mdebug frame.  */
371130803Smarcel  proc_desc = find_proc_desc (pc);
372130803Smarcel  if (proc_desc == NULL)
373130803Smarcel    return NULL;
374130803Smarcel
375130803Smarcel  return &alpha_mdebug_frame_base;
376130803Smarcel}
377130803Smarcel
378130803Smarcel
379130803Smarcelvoid
380130803Smarcelalpha_mdebug_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
381130803Smarcel{
382130803Smarcel  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
383130803Smarcel
384130803Smarcel  frame_unwind_append_sniffer (gdbarch, alpha_mdebug_frame_sniffer);
385130803Smarcel  frame_base_append_sniffer (gdbarch, alpha_mdebug_frame_base_sniffer);
386130803Smarcel}
387