#include "symfile.h"
#include "objfiles.h"
+#include "opcode/mips.h"
+
#define VM_MIN_ADDRESS (unsigned)0x400000
\f
+static int mips_in_lenient_prologue PARAMS ((CORE_ADDR, CORE_ADDR));
+
/* Some MIPS boards don't support floating point, so we permit the
user to turn it off. */
int mips_fpu = 1;
decstation). 22apr93 rich@cygnus.com. */
if (!stop_soon_quietly)
{
+ static int blurb_printed = 0;
+
if (fence == VM_MIN_ADDRESS)
warning("Hit beginning of text section without finding");
else
warning("Hit heuristic-fence-post without finding");
- warning("enclosing function for pc 0x%x", pc);
+ warning("enclosing function for address 0x%x", pc);
+ if (!blurb_printed)
+ {
+ printf_filtered ("\
+This warning occurs if you are debugging a function without any symbols\n\
+(for example, in a stripped executable). In that case, you may wish to\n\
+increase the size of the search with the `set heuristic-fence-post' command.\n\
+\n\
+Otherwise, you told GDB there was a function where there isn't one, or\n\
+(more likely) you have encountered a bug in GDB.\n");
+ blurb_printed = 1;
+ }
}
return 0;
unsigned long reg_mask = 0;
if (start_pc == 0) return NULL;
- bzero(&temp_proc_desc, sizeof(temp_proc_desc));
- bzero(&temp_saved_regs, sizeof(struct frame_saved_regs));
+ memset(&temp_proc_desc, '\0', sizeof(temp_proc_desc));
+ memset(&temp_saved_regs, '\0', sizeof(struct frame_saved_regs));
PROC_LOW_ADDR(&temp_proc_desc) = start_pc;
if (start_pc + 200 < limit_pc) limit_pc = start_pc + 200;
{
mips_extra_func_info_t proc_desc;
struct block *b = block_for_pc(pc);
- struct symbol *sym =
- b ? lookup_symbol(MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, 0, NULL) : NULL;
+ struct symbol *sym;
+ CORE_ADDR startaddr;
+
+ find_pc_partial_function (pc, NULL, &startaddr, NULL);
+ if (b == NULL)
+ sym = NULL;
+ else
+ {
+ if (startaddr > BLOCK_START (b))
+ /* This is the "pathological" case referred to in a comment in
+ print_frame_info. It might be better to move this check into
+ symbol reading. */
+ sym = NULL;
+ else
+ sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE,
+ 0, NULL);
+ }
if (sym)
{
if (PROC_LOW_ADDR(&link->info) <= pc
&& PROC_HIGH_ADDR(&link->info) > pc)
return &link->info;
+
+ if (startaddr == 0)
+ startaddr = heuristic_proc_start (pc);
+
proc_desc =
- heuristic_proc_desc(heuristic_proc_start(pc), pc, next_frame);
+ heuristic_proc_desc (startaddr, pc, next_frame);
}
return proc_desc;
}
return 0;
cached_proc_desc = proc_desc;
- return read_next_frame_reg(frame, PROC_FRAME_REG(proc_desc))
- + PROC_FRAME_OFFSET(proc_desc);
+
+ /* If no frame pointer and frame size is zero, we must be at end
+ of stack (or otherwise hosed). If we don't check frame size,
+ we loop forever if we see a zero size frame. */
+ if (PROC_FRAME_REG (proc_desc) == SP_REGNUM
+ && PROC_FRAME_OFFSET (proc_desc) == 0)
+ return 0;
+ else
+ return read_next_frame_reg(frame, PROC_FRAME_REG(proc_desc))
+ + PROC_FRAME_OFFSET(proc_desc);
}
void
{
extern struct obstack frame_cache_obstack;
/* Use proc_desc calculated in frame_chain */
- mips_extra_func_info_t proc_desc = fci->next ? cached_proc_desc :
- find_proc_desc(fci->pc, fci->next);
+ mips_extra_func_info_t proc_desc =
+ fci->next ? cached_proc_desc : find_proc_desc(fci->pc, fci->next);
fci->saved_regs = (struct frame_saved_regs*)
obstack_alloc (&frame_cache_obstack, sizeof(struct frame_saved_regs));
- bzero(fci->saved_regs, sizeof(struct frame_saved_regs));
+ memset (fci->saved_regs, 0, sizeof (struct frame_saved_regs));
fci->proc_desc =
- proc_desc == &temp_proc_desc ? 0 : proc_desc;
+ proc_desc == &temp_proc_desc ? 0 : proc_desc;
if (proc_desc)
{
int ireg;
fci->frame = READ_FRAME_REG(fci, PROC_FRAME_REG(proc_desc))
+ PROC_FRAME_OFFSET(proc_desc);
+ /* If this is the innermost frame, and we are still in the
+ prologue (loosely defined), then the registers may not have
+ been saved yet. */
+ if (fci->next == NULL
+ && !PROC_DESC_IS_DUMMY(proc_desc)
+ && mips_in_lenient_prologue (PROC_LOW_ADDR (proc_desc), fci->pc))
+ {
+ /* Can't just say that the registers are not saved, because they
+ might get clobbered halfway through the prologue.
+ heuristic_proc_desc already has the right code to figure out
+ exactly what has been saved, so use it. As far as I know we
+ could be doing this (as we do on the 68k, for example)
+ regardless of whether we are in the prologue; I'm leaving in
+ the check for being in the prologue only out of conservatism
+ (I'm not sure whether heuristic_proc_desc handles all cases,
+ for example).
+
+ This stuff is ugly (and getting uglier by the minute). Probably
+ the best way to clean it up is to ignore the proc_desc's from
+ the symbols altogher, and get all the information we need by
+ examining the prologue (provided we can make the prologue
+ examining code good enough to get all the cases...). */
+ proc_desc =
+ heuristic_proc_desc (PROC_LOW_ADDR (proc_desc),
+ fci->pc,
+ fci->next);
+ }
+
if (proc_desc == &temp_proc_desc)
- *fci->saved_regs = temp_saved_regs;
+ *fci->saved_regs = temp_saved_regs;
else
- {
+ {
/* find which general-purpose registers were saved */
reg_position = fci->frame + PROC_REG_OFFSET(proc_desc);
mask = kernel_trap ? 0xFFFFFFFF : PROC_REG_MASK(proc_desc);
for (ireg= 31; mask; --ireg, mask <<= 1)
- if (mask & 0x80000000)
+ if (mask & 0x80000000)
{
- fci->saved_regs->regs[ireg] = reg_position;
- reg_position -= 4;
+ fci->saved_regs->regs[ireg] = reg_position;
+ reg_position -= 4;
}
/* find which floating-point registers were saved */
reg_position = fci->frame + PROC_FREG_OFFSET(proc_desc);
- /* The freg_offset points to where the first *double* register is saved.
- * So skip to the high-order word. */
+
+ /* The freg_offset points to where the first *double* register
+ is saved. So skip to the high-order word. */
reg_position += 4;
mask = kernel_trap ? 0xFFFFFFFF : PROC_FREG_MASK(proc_desc);
for (ireg = 31; mask; --ireg, mask <<= 1)
- if (mask & 0x80000000)
+ if (mask & 0x80000000)
{
- fci->saved_regs->regs[FP0_REGNUM+ireg] = reg_position;
- reg_position -= 4;
+ fci->saved_regs->regs[FP0_REGNUM+ireg] = reg_position;
+ reg_position -= 4;
}
- }
+ }
/* hack: if argument regs are saved, guess these contain args */
if ((PROC_REG_MASK(proc_desc) & 0xF0) == 0) fci->num_args = -1;
mips_print_register (regnum, all)
int regnum, all;
{
- unsigned char raw_buffer[MAX_REGISTER_RAW_SIZE];
- REGISTER_TYPE val;
+ unsigned char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ REGISTER_TYPE val;
- /* Get the data in raw format. */
- if (read_relative_register_raw_bytes (regnum, raw_buffer))
- {
- printf_filtered ("%s: [Invalid]", reg_names[regnum]);
- return;
- }
-
- /* If an even floating pointer register, also print as double. */
- if (regnum >= FP0_REGNUM && regnum < FP0_REGNUM+32
- && !((regnum-FP0_REGNUM) & 1)) {
- char dbuffer[MAX_REGISTER_RAW_SIZE];
-
- read_relative_register_raw_bytes (regnum, dbuffer);
- read_relative_register_raw_bytes (regnum+1, dbuffer+4);
+ /* Get the data in raw format. */
+ if (read_relative_register_raw_bytes (regnum, raw_buffer))
+ {
+ printf_filtered ("%s: [Invalid]", reg_names[regnum]);
+ return;
+ }
+
+ /* If an even floating pointer register, also print as double. */
+ if (regnum >= FP0_REGNUM && regnum < FP0_REGNUM+32
+ && !((regnum-FP0_REGNUM) & 1)) {
+ char dbuffer[MAX_REGISTER_RAW_SIZE];
+
+ read_relative_register_raw_bytes (regnum, dbuffer);
+ read_relative_register_raw_bytes (regnum+1, dbuffer+4);
#ifdef REGISTER_CONVERT_TO_TYPE
- REGISTER_CONVERT_TO_TYPE(regnum, builtin_type_double, dbuffer);
-#endif
- printf_filtered ("(d%d: ", regnum-FP0_REGNUM);
- val_print (builtin_type_double, dbuffer, 0,
- stdout, 0, 1, 0, Val_pretty_default);
- printf_filtered ("); ");
- }
- fputs_filtered (reg_names[regnum], stdout);
-#ifndef NUMERIC_REG_NAMES
- if (regnum < 32)
- printf_filtered ("(r%d): ", regnum);
- else
+ REGISTER_CONVERT_TO_TYPE(regnum, builtin_type_double, dbuffer);
#endif
- printf_filtered (": ");
+ printf_filtered ("(d%d: ", regnum-FP0_REGNUM);
+ val_print (builtin_type_double, dbuffer, 0,
+ stdout, 0, 1, 0, Val_pretty_default);
+ printf_filtered ("); ");
+ }
+ fputs_filtered (reg_names[regnum], stdout);
+
+ /* The problem with printing numeric register names (r26, etc.) is that
+ the user can't use them on input. Probably the best solution is to
+ fix it so that either the numeric or the funky (a2, etc.) names
+ are accepted on input. */
+ if (regnum < 32)
+ printf_filtered ("(r%d): ", regnum);
+ else
+ printf_filtered (": ");
- /* If virtual format is floating, print it that way. */
- if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT
- && ! INVALID_FLOAT (raw_buffer, REGISTER_VIRTUAL_SIZE(regnum))) {
- val_print (REGISTER_VIRTUAL_TYPE (regnum), raw_buffer, 0,
- stdout, 0, 1, 0, Val_pretty_default);
- }
- /* Else print as integer in hex. */
- else
- {
- long val;
+ /* If virtual format is floating, print it that way. */
+ if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT
+ && ! INVALID_FLOAT (raw_buffer, REGISTER_VIRTUAL_SIZE(regnum))) {
+ val_print (REGISTER_VIRTUAL_TYPE (regnum), raw_buffer, 0,
+ stdout, 0, 1, 0, Val_pretty_default);
+ }
+ /* Else print as integer in hex. */
+ else
+ {
+ long val;
- val = extract_signed_integer (raw_buffer,
- REGISTER_RAW_SIZE (regnum));
+ val = extract_signed_integer (raw_buffer,
+ REGISTER_RAW_SIZE (regnum));
- if (val == 0)
- printf_filtered ("0");
- else if (all)
- printf_filtered (local_hex_format(), val);
- else
- printf_filtered ("%s=%d", local_hex_string(val), val);
- }
+ if (val == 0)
+ printf_filtered ("0");
+ else if (all)
+ /* FIXME: We should be printing this in a fixed field width, so that
+ registers line up. */
+ printf_filtered (local_hex_format(), val);
+ else
+ printf_filtered ("%s=%d", local_hex_string(val), val);
+ }
}
/* Replacement for generic do_registers_info. */
return -1;
}
\f
-/* To skip prologues, I use this predicate. Returns either PC
- itself if the code at PC does not look like a function prologue;
- otherwise returns an address that (if we're lucky) follows
- the prologue. */
+/* Is this a branch with a delay slot? */
+static int
+is_delayed (insn)
+ unsigned long insn;
+{
+ int i;
+ for (i = 0; i < NUMOPCODES; ++i)
+ if (mips_opcodes[i].pinfo != INSN_MACRO
+ && (insn & mips_opcodes[i].mask) == mips_opcodes[i].match)
+ break;
+ return (i < NUMOPCODES
+ && (mips_opcodes[i].pinfo & (INSN_UNCOND_BRANCH_DELAY
+ | INSN_COND_BRANCH_DELAY
+ | INSN_COND_BRANCH_LIKELY)));
+}
+
+/* To skip prologues, I use this predicate. Returns either PC itself
+ if the code at PC does not look like a function prologue; otherwise
+ returns an address that (if we're lucky) follows the prologue. If
+ LENIENT, then we must skip everything which is involved in setting
+ up the frame (it's OK to skip more, just so long as we don't skip
+ anything which might clobber the registers which are being saved.
+ We must skip more in the case where part of the prologue is in the
+ delay slot of a non-prologue instruction). */
CORE_ADDR
-mips_skip_prologue(pc)
+mips_skip_prologue (pc, lenient)
CORE_ADDR pc;
+ int lenient;
{
struct symbol *f;
struct block *b;
/* Skip the typical prologue instructions. These are the stack adjustment
instruction and the instructions that save registers on the stack
or in the gcc frame. */
- for (offset = 0; offset < 100; offset += 4) {
- inst = read_memory_integer(pc + offset, 4);
+ for (offset = 0; offset < 100; offset += 4)
+ {
+ char buf[4];
+ int status;
+
+ status = read_memory_nobpt (pc + offset, buf, 4);
+ if (status)
+ memory_error (status, pc + offset);
+ inst = extract_unsigned_integer (buf, 4);
+
+ if (lenient && is_delayed (inst))
+ continue;
+
if ((inst & 0xffff0000) == 0x27bd0000) /* addiu $sp,$sp,offset */
seen_sp_adjust = 1;
else if ((inst & 0xFFE00000) == 0xAFA00000 && (inst & 0x001F0000))
#endif
}
+/* Is address PC in the prologue (loosely defined) for function at
+ STARTADDR? */
+
+static int
+mips_in_lenient_prologue (startaddr, pc)
+ CORE_ADDR startaddr;
+ CORE_ADDR pc;
+{
+ CORE_ADDR end_prologue = mips_skip_prologue (startaddr, 1);
+ return pc >= startaddr && pc < end_prologue;
+}
+
/* Given a return value in `regbuf' with a type `valtype',
extract and copy its value into `valbuf'. */
void
write_register_bytes(REGISTER_BYTE (regnum), raw_buffer, TYPE_LENGTH (valtype));
}
-/* Let the user turn off floating point and set the fence post for
- heuristic_proc_start. */
+static void reinit_frame_cache_sfunc PARAMS ((char *, int
+ struct cmd_list_element *));
+
+/* Just like reinit_frame_cache, but with the right arguments to be
+ callable as an sfunc. */
+static void
+reinit_frame_cache_sfunc (args, from_tty, c)
+ char *args;
+ int from_tty;
+ struct cmd_list_element *c;
+{
+ reinit_frame_cache ();
+}
void
_initialize_mips_tdep ()
{
+ struct cmd_list_element *c;
+
+ /* Let the user turn off floating point and set the fence post for
+ heuristic_proc_start. */
+
add_show_from_set
(add_set_cmd ("mipsfpu", class_support, var_boolean,
(char *) &mips_fpu,
or dealing with return values.", &setlist),
&showlist);
- add_show_from_set
- (add_set_cmd ("heuristic-fence-post", class_support, var_uinteger,
- (char *) &heuristic_fence_post,
- "Set the distance searched for the start of a function.\n\
-Set number of bytes to be searched backward to find the beginning of a\n\
-function without symbols.", &setlist),
- &showlist);
+ /* We really would like to have both "0" and "unlimited" work, but
+ command.c doesn't deal with that. So make it a var_zinteger
+ because the user can always use "999999" or some such for unlimited. */
+ c = add_set_cmd ("heuristic-fence-post", class_support, var_zinteger,
+ (char *) &heuristic_fence_post,
+ "\
+Set the distance searched for the start of a function.\n\
+If you are debugging a stripped executable, GDB needs to search through the\n\
+program for the start of a function. This command sets the distance of the\n\
+search. The only need to set it is when debugging a stripped executable.",
+ &setlist);
+ /* We need to throw away the frame cache when we set this, since it
+ might change our ability to get backtraces. */
+ c->function.sfunc = reinit_frame_cache_sfunc;
+ add_show_from_set (c, &showlist);
}