diff options
Diffstat (limited to 'gdb/blockframe.c')
-rw-r--r-- | gdb/blockframe.c | 384 |
1 files changed, 211 insertions, 173 deletions
diff --git a/gdb/blockframe.c b/gdb/blockframe.c index 451af1a..3ea5919 100644 --- a/gdb/blockframe.c +++ b/gdb/blockframe.c @@ -1,35 +1,48 @@ /* Get info from stack frames; convert between frames, blocks, functions and pc values. - Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc. + Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc. -GDB is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY. No author or distributor accepts responsibility to anyone -for the consequences of using it or for whether it serves any -particular purpose or works at all, unless he says so in writing. -Refer to the GDB General Public License for full details. +This file is part of GDB. -Everyone is granted permission to copy, modify and redistribute GDB, -but only under the conditions described in the GDB General Public -License. A copy of this license is supposed to have been given to you -along with GDB so you can know your rights and responsibilities. It -should be in a file named COPYING. Among other things, the copyright -notice and this notice must be preserved on all copies. +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. -In other words, go ahead and share GDB, but don't try to stop -anyone else from sharing it farther. Help stamp out software hoarding! -*/ +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "defs.h" #include "param.h" #include "symtab.h" #include "frame.h" -/* Address of end of first object file. +#include <obstack.h> + +/* Start and end of object file containing the entry point. + STARTUP_FILE_END is the first address of the next file. This file is assumed to be a startup file and frames with pc's inside it - are treated as nonexistent. */ + are treated as nonexistent. + + Setting these variables is necessary so that backtraces do not fly off + the bottom of the stack. */ +CORE_ADDR startup_file_start; +CORE_ADDR startup_file_end; -CORE_ADDR first_object_file_end; +/* Is ADDR outside the startup file? */ +int +outside_startup_file (addr) + CORE_ADDR addr; +{ + return !(addr >= startup_file_start && addr < startup_file_end); +} /* Address of innermost stack frame (contents of FP register) */ @@ -100,6 +113,18 @@ get_prev_frame (frame) return get_prev_frame_info (frame); } +/* Return the frame that FRAME calls (0 if FRAME is the innermost + frame). */ + +FRAME +get_next_frame (frame) + FRAME frame; +{ + /* We're allowed to know that FRAME and "struct frame_info *" are + the same */ + return frame->next; +} + /* * Flush the entire frame cache. */ @@ -109,7 +134,7 @@ flush_cached_frames () /* Since we can't really be sure what the first object allocated was */ obstack_free (&frame_cache_obstack, 0); obstack_init (&frame_cache_obstack); - + current_frame = (struct frame_info *) 0; /* Invalidate cache */ } @@ -127,6 +152,33 @@ get_frame_info (frame) return frame; } +/* If a machine allows frameless functions, it should define a macro + FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) in param.h. FI is the struct + frame_info for the frame, and FRAMELESS should be set to nonzero + if it represents a frameless function invocation. */ + +/* Many machines which allow frameless functions can detect them using + this macro. Such machines should define FRAMELESS_FUNCTION_INVOCATION + to just call this macro. */ +#define FRAMELESS_LOOK_FOR_PROLOGUE(FI, FRAMELESS) \ +{ \ + CORE_ADDR func_start, after_prologue; \ + func_start = (get_pc_function_start ((FI)->pc) + \ + FUNCTION_START_OFFSET); \ + if (func_start) \ + { \ + after_prologue = func_start; \ + SKIP_PROLOGUE (after_prologue); \ + (FRAMELESS) = (after_prologue == func_start); \ + } \ + else \ + /* If we can't find the start of the function, we don't really */ \ + /* know whether the function is frameless, but we should be */ \ + /* able to get a reasonable (i.e. best we can do under the */ \ + /* circumstances) backtrace by saying that it isn't. */ \ + (FRAMELESS) = 0; \ +} + /* Return a structure containing various interesting information about the frame that called NEXT_FRAME. */ @@ -138,16 +190,6 @@ get_prev_frame_info (next_frame) struct frame_info *prev; int fromleaf = 0; - /* If we are within "start" right now, don't go any higher. */ - /* This truncates stack traces of things at sigtramp() though, - because sigtramp() doesn't have a normal return PC, it has - garbage or a small value (seen: 3) in the return PC slot. - It's VITAL to see where the signal occurred, so punt this. */ -#if 0 - if (next_frame && next_frame->pc < first_object_file_end) - return 0; -#endif - /* If the requested entry is in the cache, return it. Otherwise, figure out what the address should be for the entry we're about to add to the cache. */ @@ -155,61 +197,58 @@ get_prev_frame_info (next_frame) if (!next_frame) { if (!current_frame) - error ("No frame is currently selected."); + { + if (!have_inferior_p () && !have_core_file_p ()) + fatal ("get_prev_frame_info: Called before cache primed. \"Shouldn't happen.\""); + else + error ("No inferior or core file."); + } return current_frame; } - else + + /* If we have the prev one, return it */ + if (next_frame->prev) + return next_frame->prev; + + /* On some machines it is possible to call a function without + setting up a stack frame for it. On these machines, we + define this macro to take two args; a frameinfo pointer + identifying a frame and a variable to set or clear if it is + or isn't leafless. */ +#ifdef FRAMELESS_FUNCTION_INVOCATION + /* Still don't want to worry about this except on the innermost + frame. This macro will set FROMLEAF if NEXT_FRAME is a + frameless function invocation. */ + if (!(next_frame->next)) { - /* If we have the prev one, return it */ - if (next_frame->prev) - return next_frame->prev; - - /* There is a questionable, but probably always correct - assumption being made here. The assumption is that if - functions on a specific machine has a FUNCTION_START_OFFSET, - then this is used by the function call instruction for some - purpose. If the function call instruction has this much hair - in it, it probably also sets up the frame pointer - automatically (ie. we'll never have what I am calling a - "leaf node", one which shares a frame pointer with it's - calling function). This is true on a vax. The only other - way to find this out would be to setup a seperate macro - "FUNCTION_HAS_FRAME_POINTER", which would often be equivalent - to SKIP_PROLOGUE modifying a pc value. */ - -#if FUNCTION_START_OFFSET == 0 - if (!(next_frame->next)) - { - /* Innermost */ - CORE_ADDR func_start, after_prologue; - - func_start = (get_pc_function_start (next_frame->pc) + - FUNCTION_START_OFFSET); - after_prologue = func_start; - SKIP_PROLOGUE (after_prologue); - if (after_prologue == func_start) - { - fromleaf = 1; - address = next_frame->frame; - } - } + FRAMELESS_FUNCTION_INVOCATION (next_frame, fromleaf); + if (fromleaf) + address = next_frame->frame; + } #endif - if (!fromleaf) - { - /* Two macros defined in param.h specify the machine-dependent - actions to be performed here. */ - /* First, get the frame's chain-pointer. - If that is zero, the frame is the outermost frame. */ - address = FRAME_CHAIN (next_frame); - if (!FRAME_CHAIN_VALID (address, next_frame)) - return 0; - - /* If frame has a caller, combine the chain pointer and - the frame's own address to get the address of the caller. */ - address = FRAME_CHAIN_COMBINE (address, next_frame); - } + if (!fromleaf) + { + /* Two macros defined in param.h specify the machine-dependent + actions to be performed here. + First, get the frame's chain-pointer. + If that is zero, the frame is the outermost frame or a leaf + called by the outermost frame. This means that if start + calls main without a frame, we'll return 0 (which is fine + anyway). + + Nope; there's a problem. This also returns when the current + routine is a leaf of main. This is unacceptable. We move + this to after the ffi test; I'd rather have backtraces from + start go curfluy than have an abort called from main not show + main. */ + address = FRAME_CHAIN (next_frame); + if (!FRAME_CHAIN_VALID (address, next_frame)) + return 0; + /* If this frame is a leaf, this will be superceeded by the + code below. */ + address = FRAME_CHAIN_COMBINE (address, next_frame); } prev = (struct frame_info *) @@ -252,102 +291,7 @@ get_frame_saved_regs (frame_info_addr, saved_regs_addr) struct frame_info *frame_info_addr; struct frame_saved_regs *saved_regs_addr; { -#if 1 FRAME_FIND_SAVED_REGS (frame_info_addr, *saved_regs_addr); -#else - { - register int regnum; - register int regmask; - register CORE_ADDR next_addr; - register CORE_ADDR pc; - int nextinsn; - bzero (&*saved_regs_addr, sizeof *saved_regs_addr); - if ((frame_info_addr)->pc >= ((frame_info_addr)->frame - - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4) - && (frame_info_addr)->pc <= (frame_info_addr)->frame) - { - next_addr = (frame_info_addr)->frame; - pc = (frame_info_addr)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; - } - else - { - pc = get_pc_function_start ((frame_info_addr)->pc); - /* Verify we have a link a6 instruction next; - if not we lose. If we win, find the address above the saved - regs using the amount of storage from the link instruction. */ - if (044016 == read_memory_integer (pc, 2)) - { - next_addr = (frame_info_addr)->frame + read_memory_integer (pc += 2, 4); - pc += 4; - } - else if (047126 == read_memory_integer (pc, 2)) - { - next_addr = (frame_info_addr)->frame + read_memory_integer (pc += 2, 2); - pc+=2; - } - else goto lose; - - /* If have an addal #-n, sp next, adjust next_addr. */ - if ((0177777 & read_memory_integer (pc, 2)) == 0157774) - { - next_addr += read_memory_integer (pc += 2, 4); - pc += 4; - } - } - /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ - regmask = read_memory_integer (pc + 2, 2); - - /* But before that can come an fmovem. Check for it. */ - nextinsn = 0xffff & read_memory_integer (pc, 2); - if (0xf227 == nextinsn - && (regmask & 0xff00) == 0xe000) - { - pc += 4; /* Regmask's low bit is for register fp7, the first pushed */ - for (regnum = FP0_REGNUM + 7; - regnum >= FP0_REGNUM; - regnum--, regmask >>= 1) - if (regmask & 1) - (*saved_regs_addr).regs[regnum] = (next_addr -= 12); - regmask = read_memory_integer (pc + 2, 2); - } - if (0044327 == read_memory_integer (pc, 2)) - { - pc += 4; /* Regmask's low bit is for register 0, the first written */ - for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) - if (regmask & 1) - (*saved_regs_addr).regs[regnum] = (next_addr += 4) - 4; - } - else if (0044347 == read_memory_integer (pc, 2)) - { pc += 4; /* Regmask's low bit is for register 15, the first pushed */ - for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) - if (regmask & 1) - (*saved_regs_addr).regs[regnum] = (next_addr -= 4); } - else if (0x2f00 == (0xfff0 & read_memory_integer (pc, 2))) - { regnum = 0xf & read_memory_integer (pc, 2); pc += 2; - (*saved_regs_addr).regs[regnum] = (next_addr -= 4); } - /* fmovemx to index of sp may follow. */ - regmask = read_memory_integer (pc + 2, 2); - nextinsn = 0xffff & read_memory_integer (pc, 2); - if (0xf236 == nextinsn - && (regmask & 0xff00) == 0xf000) - { - pc += 10; /* Regmask's low bit is for register fp0, the first written */ - for (regnum = FP0_REGNUM + 7; - regnum >= FP0_REGNUM; - regnum--, regmask >>= 1) - if (regmask & 1) - (*saved_regs_addr).regs[regnum] = (next_addr += 12) - 12; - regmask = read_memory_integer (pc + 2, 2); - } - /* clrw -(sp); movw ccr,-(sp) may follow. */ - if (0x426742e7 == read_memory_integer (pc, 4)) - (*saved_regs_addr).regs[PS_REGNUM] = (next_addr -= 4); - lose: ; - (*saved_regs_addr).regs[SP_REGNUM] = (frame_info_addr)->frame + 8; - (*saved_regs_addr).regs[FP_REGNUM] = (frame_info_addr)->frame; - (*saved_regs_addr).regs[PC_REGNUM] = (frame_info_addr)->frame + 4; - } -#endif } /* Return the innermost lexical block in execution @@ -430,6 +374,8 @@ block_for_pc (pc) if (ps->textlow <= pc && ps->texthigh > pc) { + if (ps->readin) + fatal ("Internal error: pc found in readin psymtab and not in any symtab."); s = psymtab_to_symtab (ps); bl = BLOCKVECTOR (s); b = BLOCKVECTOR_BLOCK (bl, 0); @@ -482,6 +428,91 @@ find_pc_function (pc) return block_function (b); } +/* Finds the "function" (text symbol) that is smaller than PC + but greatest of all of the potential text symbols. Sets + *NAME and/or *ADDRESS conditionally if that pointer is non-zero. + Returns 0 if it couldn't find anything, 1 if it did. */ + +int +find_pc_partial_function (pc, name, address) + CORE_ADDR pc; + char **name; + CORE_ADDR *address; +{ + struct partial_symtab *pst = find_pc_psymtab (pc); + struct symbol *f; + int miscfunc; + struct partial_symbol *psb; + + if (pst) + { + if (pst->readin) + { + /* The information we want has already been read in. + We can go to the already readin symbols and we'll get + the best possible answer. */ + f = find_pc_function (pc); + if (!f) + { + /* No availible symbol. */ + if (name != 0) + *name = 0; + if (address != 0) + *address = 0; + return 0; + } + + if (name) + *name = SYMBOL_NAME (f); + if (address) + *address = SYMBOL_VALUE (f); + } + + /* Get the information from a combination of the pst + (static symbols), and the misc function vector (extern + symbols). */ + miscfunc = find_pc_misc_function (pc); + psb = find_pc_psymbol (pst, pc); + + if (!psb && miscfunc == -1) + { + if (address != 0) + *address = 0; + if (name != 0) + *name = 0; + return 0; + } + if (!psb + || (miscfunc != -1 + && SYMBOL_VALUE(psb) < misc_function_vector[miscfunc].address)) + { + if (address) + *address = misc_function_vector[miscfunc].address; + if (name) + *name = misc_function_vector[miscfunc].name; + } + else + { + if (address) + *address = SYMBOL_VALUE (psb); + if (name) + *name = SYMBOL_NAME (psb); + } + } + else + /* Must be in the misc function stuff. */ + { + miscfunc = find_pc_misc_function (pc); + if (miscfunc == -1) + return 0; + if (address) + *address = misc_function_vector[miscfunc].address; + if (name) + *name = misc_function_vector[miscfunc].name; + } + return 1; +} + /* Find the misc function whose address is the largest while being less than PC. Return its index in misc_function_vector. Returns -1 if PC is not in suitable range. */ @@ -496,6 +527,8 @@ find_pc_misc_function (pc) register int distance; /* Note that the last thing in the vector is always _etext. */ + /* Actually, "end", now that non-functions + go on the misc_function_vector. */ /* Above statement is not *always* true - fix for case where there are */ /* no misc functions at all (ie no symbol table has been read). */ @@ -506,6 +539,11 @@ find_pc_misc_function (pc) pc > misc_function_vector[hi].address) return -1; + /* Note that the following search will not return hi if + pc == misc_function_vector[hi].address. If "end" points to the + first unused location, this is correct and the above test + simply needs to be changed to + "pc >= misc_function_vector[hi].address". */ do { new = (lo + hi) >> 1; distance = misc_function_vector[new].address - pc; |