diff options
author | gdb-3.1 <gdb@fsf.org> | 1989-01-31 17:56:40 +0000 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2012-06-03 15:36:31 +0100 |
commit | e91b87a36830d061ef87d67be5f309e4d4ed918f (patch) | |
tree | 3408ea913a9cccd51c9b7d0b3bc7d7897cac8a5b /gdb/sparc-dep.c | |
parent | bb7592f01006b09c846831a9fb9c306307ba34f6 (diff) | |
download | gdb-e91b87a36830d061ef87d67be5f309e4d4ed918f.zip gdb-e91b87a36830d061ef87d67be5f309e4d4ed918f.tar.gz gdb-e91b87a36830d061ef87d67be5f309e4d4ed918f.tar.bz2 |
gdb-3.1
Diffstat (limited to 'gdb/sparc-dep.c')
-rw-r--r-- | gdb/sparc-dep.c | 932 |
1 files changed, 932 insertions, 0 deletions
diff --git a/gdb/sparc-dep.c b/gdb/sparc-dep.c new file mode 100644 index 0000000..2d53a04 --- /dev/null +++ b/gdb/sparc-dep.c @@ -0,0 +1,932 @@ +/* Machine-dependent code which would otherwise be in inflow.c and core.c, + for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + This code is for the sparc cpu. + +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. + +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. + +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! +*/ + +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "obstack.h" +#include "sparc-opcode.h" +#include "gdbcore.h" + +#include <stdio.h> +#include <sys/param.h> +#include <sys/dir.h> +#include <sys/user.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <fcntl.h> + +#include <sys/ptrace.h> +#include <machine/reg.h> + +#include <a.out.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/core.h> + +extern int errno; +extern int attach_flag; + +/* This function simply calls ptrace with the given arguments. + It exists so that all calls to ptrace are isolated in this + machine-dependent file. */ +int +call_ptrace (request, pid, arg3, arg4) + int request, pid, arg3, arg4; +{ + return ptrace (request, pid, arg3, arg4); +} + +void +kill_inferior () +{ + if (remote_debugging) + return; + if (inferior_pid == 0) + return; + ptrace (8, inferior_pid, 0, 0); + wait (0); + inferior_died (); +} + +/* This is used when GDB is exiting. It gives less chance of error.*/ + +void +kill_inferior_fast () +{ + if (remote_debugging) + return; + if (inferior_pid == 0) + return; + ptrace (8, inferior_pid, 0, 0); + wait (0); +} + +/* Simulate single-step ptrace call for sun4. Code written by Gary + Beihl (beihl@mcc.com). */ + +/* + * Duplicated from breakpoint.c because (at least for now) this is a + * machine dependent routine. + */ +static char break_insn[] = BREAKPOINT; + +/* From infrun.c */ +extern int stop_after_trap, stop_after_attach; + +static CORE_ADDR next_pc, npc4, target; +static int brknpc4, brktrg; +typedef char binsn_quantum[sizeof break_insn]; +static binsn_quantum break_mem[3]; + +/* Non-zero if we just simulated a single-step ptrace call. This is + needed because we cannot remove the breakpoints in the inferior + process until after the `wait' in `wait_for_inferior'. Used for + sun4. */ + +int one_stepped; + +void +single_step (signal) + int signal; +{ + branch_type br, isannulled(); + CORE_ADDR pc; + + next_pc = read_register (NPC_REGNUM); + npc4 = next_pc + 4; /* branch not taken */ + + if (!one_stepped) + { + /* Always set breakpoint for NPC. */ + read_memory (next_pc, break_mem[0], sizeof break_insn); + write_memory (next_pc, break_insn, sizeof break_insn); + /* printf ("set break at %x\n",next_pc); */ + + pc = read_register (PC_REGNUM); + br = isannulled (pc, &target); + brknpc4 = brktrg = 0; + + if (br == bicca) + { + /* Conditional annulled branch will either end up at + npc (if taken) or at npc+4 (if not taken). Trap npc+4. */ + brknpc4 = 1; + read_memory (npc4, break_mem[1], sizeof break_insn); + write_memory (npc4, break_insn, sizeof break_insn); + } + else if (br == baa && target != next_pc) + { + /* Unconditional annulled branch will always end up at + the target. */ + brktrg = 1; + read_memory (target, break_mem[2], sizeof break_insn); + write_memory (target, break_insn, sizeof break_insn); + } + + /* Let it go */ + ptrace (7, inferior_pid, 1, signal); + one_stepped = 1; + return; + } + else + { + /* Remove breakpoints */ + write_memory (next_pc, break_mem[0], sizeof break_insn); + + if (brknpc4) + { + write_memory (npc4, break_mem[1], sizeof break_insn); + } + if (brktrg) + { + write_memory (target, break_mem[2], sizeof break_insn); + } + one_stepped = 0; + } +} + +/* Resume execution of the inferior process. + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. */ + +void +resume (step, signal) + int step; + int signal; +{ + errno = 0; + if (remote_debugging) + remote_resume (step, signal); + else + { + /* Sparc doesn't have single step on ptrace */ + if (step) + single_step (signal); + else + ptrace (7, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); + } +} + +#ifdef ATTACH_DETACH + +/* Start debugging the process whose number is PID. */ + +int +attach (pid) + int pid; +{ + errno = 0; + ptrace (PTRACE_ATTACH, pid, 0, 0); + if (errno) + perror_with_name ("ptrace"); + attach_flag = 1; + return pid; +} + +/* Stop debugging the process whose number is PID + and continue it with signal number SIGNAL. + SIGNAL = 0 means just continue it. */ + +void +detach (signal) + int signal; +{ + errno = 0; + ptrace (PTRACE_DETACH, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); + attach_flag = 0; +} +#endif /* ATTACH_DETACH */ + +void +fetch_inferior_registers () +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + int cwp; + struct rwindow local_and_ins; + + if (remote_debugging) + remote_fetch_registers (registers); + else + { + ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers); + ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers); + + registers[REGISTER_BYTE (0)] = 0; + bcopy (&inferior_registers.r_g1, ®isters[REGISTER_BYTE (1)], 15 * 4); + bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof inferior_fp_registers.fpu_fr); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc; + *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)] = inferior_registers.r_npc; + *(int *)®isters[REGISTER_BYTE (Y_REGNUM)] = inferior_registers.r_y; +/* *(int *)®isters[REGISTER_BYTE (RP_REGNUM)] = + inferior_registers.r_o7 + 8; + bcopy (&inferior_fp_registers.Fpu_fsr, + ®isters[REGISTER_BYTE (FPS_REGNUM)], + sizeof (FPU_FSR_TYPE)); */ + + read_inferior_memory (inferior_registers.r_sp, + ®isters[REGISTER_BYTE (16)], + 16*4); + } +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +store_inferior_registers (regno) + int regno; +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + + if (remote_debugging) + remote_store_registers (registers); + else + { + int in_regs = 1, in_fpregs = 1, in_fparegs, in_cpregs = 1; + + if (regno >= 0) + if (FP0_REGNUM <= regno && regno <= FP0_REGNUM + 32) + in_regs = 0; + else + in_fpregs = 0; + + if (in_regs) + { + bcopy (®isters[REGISTER_BYTE (1)], + &inferior_registers.r_g1, 15 * 4); + + inferior_registers.r_ps = + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)]; + inferior_registers.r_pc = + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)]; + inferior_registers.r_npc = + *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)]; + inferior_registers.r_y = + *(int *)®isters[REGISTER_BYTE (Y_REGNUM)]; + + write_inferior_memory (*(int *)®isters[REGISTER_BYTE (SP_REGNUM)], + ®isters[REGISTER_BYTE (16)], + 16*4); + } + if (in_fpregs) + { + bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], + &inferior_fp_registers, + sizeof inferior_fp_registers.fpu_fr); + + /* bcopy (®isters[REGISTER_BYTE (FPS_REGNUM)], + &inferior_fp_registers.Fpu_fsr, + sizeof (FPU_FSR_TYPE)); + ****/ + } + + if (in_regs) + ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers); + if (in_fpregs) + ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers); + } +} + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. + On failure (cannot read from inferior, usually because address is out + of bounds) returns the value of errno. */ + +int +read_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & - sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + extern int errno; + + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + if (remote_debugging) + buffer[i] = remote_fetch_word (addr); + else + buffer[i] = ptrace (1, inferior_pid, addr, 0); + if (errno) + return errno; + } + + /* Copy appropriate bytes out of the buffer. */ + bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); + return 0; +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. + On failure (cannot write the inferior) + returns the value of errno. */ + +int +write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & - sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + extern int errno; + + /* Fill start and end extra bytes of buffer with existing memory data. */ + + if (remote_debugging) + buffer[0] = remote_fetch_word (addr); + else + buffer[0] = ptrace (1, inferior_pid, addr, 0); + + if (count > 1) + { + if (remote_debugging) + buffer[count - 1] + = remote_fetch_word (addr + (count - 1) * sizeof (int)); + else + buffer[count - 1] + = ptrace (1, inferior_pid, + addr + (count - 1) * sizeof (int), 0); + } + + /* Copy data to be written over corresponding part of buffer */ + + bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + if (remote_debugging) + remote_store_word (addr, buffer[i]); + else + ptrace (4, inferior_pid, addr, buffer[i]); + if (errno) + return errno; + } + + return 0; +} + + +/* Machine-dependent code which would otherwise be in core.c */ +/* Work with core dump and executable files, for GDB. */ + +/* Recognize COFF format systems because a.out.h defines AOUTHDR. */ +#ifdef AOUTHDR +#define COFF_FORMAT +#endif + +#ifndef N_TXTADDR +#define N_TXTADDR(hdr) 0 +#endif /* no N_TXTADDR */ + +#ifndef N_DATADDR +#define N_DATADDR(hdr) hdr.a_text +#endif /* no N_DATADDR */ + +/* Make COFF and non-COFF names for things a little more compatible + to reduce conditionals later. */ + +#ifdef COFF_FORMAT +#define a_magic magic +#endif + +#ifndef COFF_FORMAT +#define AOUTHDR struct exec +#endif + +extern char *sys_siglist[]; + +/* Hook for `exec_file_command' command to call. */ + +extern void (*exec_file_display_hook) (); + +#ifdef COFF_FORMAT +/* various coff data structures */ + +extern FILHDR file_hdr; +extern SCNHDR text_hdr; +extern SCNHDR data_hdr; + +#endif /* not COFF_FORMAT */ + +/* a.out header saved in core file. */ + +extern AOUTHDR core_aouthdr; + +/* a.out header of exec file. */ + +extern AOUTHDR exec_aouthdr; + +extern void validate_files (); + +void +core_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + extern char registers[]; + + /* Discard all vestiges of any previous core file + and mark data and stack spaces as empty. */ + + if (corefile) + free (corefile); + corefile = 0; + + if (corechan >= 0) + close (corechan); + corechan = -1; + + data_start = 0; + data_end = 0; + stack_start = STACK_END_ADDR; + stack_end = STACK_END_ADDR; + + /* Now, if a new core file was specified, open it and digest it. */ + + if (filename) + { + if (have_inferior_p ()) + error ("To look at a core file, you must kill the inferior with \"kill\"."); + corechan = open (filename, O_RDONLY, 0); + if (corechan < 0) + perror_with_name (filename); + + { + struct core corestr; + + val = myread (corechan, &corestr, sizeof corestr); + if (val < 0) + perror_with_name (filename); + if (corestr.c_magic != CORE_MAGIC) + error ("\"%s\" does not appear to be a core dump file (magic 0x%x, expected 0x%x)", + filename, corestr.c_magic, (int) CORE_MAGIC); + else if (sizeof (struct core) != corestr.c_len) + error ("\"%s\" has an invalid struct core length (%d, expected %d)", + filename, corestr.c_len, (int) sizeof (struct core)); + + /* Note that data_start and data_end don't depend on the exec file */ + data_start = N_DATADDR (corestr.c_aouthdr); + data_end = data_start + corestr.c_dsize; + stack_start = stack_end - corestr.c_ssize; + data_offset = sizeof corestr; + stack_offset = sizeof corestr + corestr.c_dsize; + + /* G0 *always* holds 0. */ + *(int *)®isters[REGISTER_BYTE (0)] = 0; + /* The globals and output registers. */ + + bcopy (&corestr.c_regs.r_g1, ((int *) registers) + 1, 15 * 4); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = corestr.c_regs.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = corestr.c_regs.r_pc; + *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)] = corestr.c_regs.r_npc; + *(int *)®isters[REGISTER_BYTE (Y_REGNUM)] = corestr.c_regs.r_y; + + /* My best guess at where to get the locals and input + registers is exactly where they usually are, right above + the stack pointer. If the core dump was caused by a bus + writing off the stack pointer (as is possible) then this + won't work, but it's worth the try. */ + { + int sp; + + sp = *(int *)®isters[REGISTER_BYTE (SP_REGNUM)]; + lseek (corechan, sp - stack_start + stack_offset, L_SET); + if (16 * 4 != myread (corechan, + ®isters[REGISTER_BYTE (16)], + 16 * 4)) + /* fprintf so user can still use gdb */ + fprintf (stderr, "Couldn't read input and local registers from core file\n"); + } + + bcopy (corestr.c_fpu.fpu_regs, + ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof corestr.c_fpu.fpu_regs); +#ifdef FPU + bcopy (&corestr.c_fpu.fpu_fsr, + ®isters[REGISTER_BYTE (FPS_REGNUM)], + sizeof (FPU_FSR_TYPE)); +#endif + + bcopy (&corestr.c_aouthdr, &core_aouthdr, sizeof (struct exec)); + + printf ("Core file is from \"%s\".\n", corestr.c_cmdname); + if (corestr.c_signo > 0) + printf ("Program terminated with signal %d, %s.\n", + corestr.c_signo, + corestr.c_signo < NSIG + ? sys_siglist[corestr.c_signo] + : "(undocumented)"); + } + if (filename[0] == '/') + corefile = savestring (filename, strlen (filename)); + else + { + corefile = concat (current_directory, "/", filename); + } + + set_current_frame ( create_new_frame (read_register (FP_REGNUM), + read_pc ())); + select_frame (get_current_frame (), 0); + validate_files (); + } + else if (from_tty) + printf ("No core file now.\n"); +} + +void +exec_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + + /* Eliminate all traces of old exec file. + Mark text segment as empty. */ + + if (execfile) + free (execfile); + execfile = 0; + text_start = 0; + text_end = 0; + exec_data_start = 0; + exec_data_end = 0; + if (execchan >= 0) + close (execchan); + execchan = -1; + + /* Now open and digest the file the user requested, if any. */ + + if (filename) + { + execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, + &execfile); + if (execchan < 0) + perror_with_name (filename); + +#ifdef COFF_FORMAT + { + int aout_hdrsize; + int num_sections; + + if (read_file_hdr (execchan, &file_hdr) < 0) + error ("\"%s\": not in executable format.", execfile); + + aout_hdrsize = file_hdr.f_opthdr; + num_sections = file_hdr.f_nscns; + + if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0) + error ("\"%s\": can't read optional aouthdr", execfile); + + if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections) < 0) + error ("\"%s\": can't read text section header", execfile); + + if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0) + error ("\"%s\": can't read data section header", execfile); + + text_start = exec_aouthdr.text_start; + text_end = text_start + exec_aouthdr.tsize; + text_offset = text_hdr.s_scnptr; + exec_data_start = exec_aouthdr.data_start; + exec_data_end = exec_data_start + exec_aouthdr.dsize; + exec_data_offset = data_hdr.s_scnptr; + exec_mtime = file_hdr.f_timdat; + } +#else /* not COFF_FORMAT */ + { + struct stat st_exec; + val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR)); + + if (val < 0) + perror_with_name (filename); + + text_start = N_TXTADDR (exec_aouthdr); + exec_data_start = N_DATADDR (exec_aouthdr); + text_offset = N_TXTOFF (exec_aouthdr); + exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text; + + text_end = text_start + exec_aouthdr.a_text; + exec_data_end = exec_data_start + exec_aouthdr.a_data; + + fstat (execchan, &st_exec); + exec_mtime = st_exec.st_mtime; + } +#endif /* not COFF_FORMAT */ + + validate_files (); + } + else if (from_tty) + printf ("No exec file now.\n"); + + /* Tell display code (if any) about the changed file name. */ + if (exec_file_display_hook) + (*exec_file_display_hook) (filename); +} + +/* + * Find the pc saved in frame FRAME. + */ +CORE_ADDR +frame_saved_pc (frame) + FRAME frame; +{ + CORE_ADDR prev_pc; + + /* If it's at the bottom, the return value's stored in i7/rp */ + if (get_current_frame () == frame) + prev_pc = GET_RWINDOW_REG (read_register (SP_REGNUM), rw_in[7]); + else + /* Wouldn't this always work? This would allow this routine to + be completely a macro. */ + prev_pc = GET_RWINDOW_REG (frame->bottom, rw_in[7]); + + return PC_ADJUST (prev_pc); +} + +/* + * Since an individual frame in the frame cache is defined by two + * arguments (a frame pointer and a stack pointer), we need two + * arguments to get info for an arbitrary stack frame. This routine + * takes two arguments and makes the cached frames look as if these + * two arguments defined a frame on the cache. This allows the rest + * of info frame to extract the important arguments without + * difficulty. + */ +FRAME +setup_arbitrary_frame (frame, stack) + FRAME_ADDR frame, stack; +{ + struct frame_info *fci; + FRAME fid = create_new_frame (frame, 0); + + if (!fid) + fatal ("internal: create_new_frame returned invalid frame id"); + + fid->bottom = stack; + + return fid; +} + +/* This code was written by Gary Beihl (beihl@mcc.com). + It was modified by Michael Tiemann (tiemann@corto.inria.fr). */ + +struct command_line *get_breakpoint_commands (); + +/* + * This routine appears to be passed a size by which to increase the + * stack. It then executes a save instruction in the inferior to + * increase the stack by this amount. Only the register window system + * should be affected by this; the program counter & etc. will not be. + * + * This instructions used for this purpose are: + * + * sethi %hi(0x0),g1 * + * add g1,0x1ee0,g1 * + * save sp,g1,sp + * sethi %hi(0x0),g1 * + * add g1,0x1ee0,g1 * + * t g0,0x1,o0 + * sethi %hi(0x0),g0 (nop) + * + * I presume that these set g1 to be the negative of the size, do a + * save (putting the stack pointer at sp - size) and restore the + * original contents of g1. A * indicates that the actual value of + * the instruction is modified below. + */ +static int save_insn_opcodes[] = { + 0x03000000, 0x82007ee0, 0x9de38001, 0x03000000, + 0x82007ee0, 0x91d02001, 0x01000000 }; + +/* Neither do_save_insn or do_restore_insn save stack configuration + (since the stack is in an indeterminate state through the call to + each of them); that responsibility of the routine which calls them. */ + +void +do_save_insn (size) + int size; +{ + int g1 = read_register (1); + CORE_ADDR sp = read_register (SP_REGNUM); + CORE_ADDR pc = read_register (PC_REGNUM); + CORE_ADDR npc = read_register (NPC_REGNUM); + CORE_ADDR fake_pc = sp - sizeof (save_insn_opcodes); + struct inferior_status inf_status; + + save_inferior_status (&inf_status, 0); /* Don't restore stack info */ + /* + * See above. + */ + save_insn_opcodes[0] = 0x03000000 | ((-size >> 10) & 0x3fffff); + save_insn_opcodes[1] = 0x82006000 | (-size & 0x3ff); + save_insn_opcodes[3] = 0x03000000 | ((g1 >> 10) & 0x3fffff); + save_insn_opcodes[4] = 0x82006000 | (g1 & 0x3ff); + write_memory (fake_pc, save_insn_opcodes, sizeof (save_insn_opcodes)); + + clear_proceed_status (); + stop_after_trap = 1; + proceed (fake_pc, 0, 0); + + write_register (PC_REGNUM, pc); + write_register (NPC_REGNUM, npc); + restore_inferior_status (&inf_status); +} + +/* + * This routine takes a program counter value. It restores the + * register window system to the frame above the current one, and sets + * the pc and npc to the correct values. + */ + +/* The following insns translate to: + + restore + t g0,0x1,o0 + sethi %hi(0x0), g0 */ + +static int restore_insn_opcodes[] = { 0x81e80000, 0x91d02001, 0x01000000 }; + +void +do_restore_insn (pc) + CORE_ADDR pc; +{ + CORE_ADDR sp = read_register (SP_REGNUM); + CORE_ADDR npc = pc + 4; + CORE_ADDR fake_pc = sp - sizeof (restore_insn_opcodes); + struct inferior_status inf_status; + + save_inferior_status (&inf_status, 0); /* Don't restore stack info */ + + if (!pc) + abort(); + + write_memory (fake_pc, restore_insn_opcodes, sizeof (restore_insn_opcodes)); + + clear_proceed_status (); + stop_after_trap = 1; + proceed (fake_pc, 0, 0); + + write_register (PC_REGNUM, pc); + write_register (NPC_REGNUM, npc); + restore_inferior_status (&inf_status); +} + +/* + * This routine should be more specific in it's actions; making sure + * that it uses the same register in the initial prologue section. + */ +CORE_ADDR +skip_prologue (pc) + CORE_ADDR pc; +{ + union + { + union insn_fmt insn; + int i; + } x; + int dest = -1; + + x.i = read_memory_integer (pc, 4); + + /* Recognize sethi insn. Record destination. */ + if (x.insn.sethi.op == 0 + && x.insn.sethi.op2 == 4) + { + dest = x.insn.sethi.rd; + pc += 4; + x.i = read_memory_integer (pc, 4); + } + + /* Recognizes an add immediate value to register to either %g1 or + the destination register recorded above. Actually, this might + well recognize several different arithmetic operations.*/ + if (x.insn.arith_imm.op == 2 + && x.insn.arith_imm.i == 1 + && (x.insn.arith_imm.rd == 1 + || x.insn.arith_imm.rd == dest)) + { + pc += 4; + x.i = read_memory_integer (pc, 4); + } + + /* This recognizes any SAVE insn. But why do the XOR and then + the compare? That's identical to comparing against 60 (as long + as there isn't any sign extension). */ + if (x.insn.arith.op == 2 + && (x.insn.arith.op3 ^ 32) == 28) + { + pc += 4; + x.i = read_memory_integer (pc, 4); + } + + /* Now we need to recognize stores into the frame from the input + registers. This recognizes all non alternate stores of input + register, into a location offset from the frame pointer. */ + while (x.insn.arith_imm.op == 3 + && (x.insn.arith_imm.op3 & 0x3c) == 4 /* Store, non-alt */ + && (x.insn.arith_imm.rd & 0x18) == 0x18 /* Input register */ + && x.insn.arith_imm.i == 1 /* Immediate mode */ + && x.insn.arith_imm.rs1 == 30 /* Off of frame pointer */ + && x.insn.arith_imm.simm >= 0x44 /* Into reserved */ + && x.insn.arith_imm.simm < 0x5b) /* stack space. */ + { + pc += 4; + x.i = read_memory_integer (pc, 4); + } + return pc; +} + +/* + * Check instruction at "addr" to see if it is an annulled branch. + * All other instructions will go to NPC or will trap. + * + * Set *target if we find a candidate branch; set to zero if not. + */ + +branch_type +isannulled (addr, target) + CORE_ADDR addr, *target; +{ + union insn_fmt instr; + branch_type val = not_branch; + long offset; /* Must be signed for sign-extend */ + + *target = 0; + instr.intval = read_memory_integer (addr, 4); + /* printf("intval = %x\n",instr.intval); */ + switch (instr.op1.op1) + { + case 0: /* Format 2 */ + switch(instr.op2.op2) + { + case 2: case 6: case 7: /* Bcc, FBcc, CBcc */ + if (instr.branch.cond == 8) + val = instr.branch.a ? baa : ba; + else + val = instr.branch.a ? bicca : bicc; + /* 22 bits, sign extended */ + offset = 4 * ((int) (instr.branch.disp << 10) >> 10); + *target = addr + offset; + break; + } + break; + } + /*printf("isannulled ret: %d\n",val); */ + return val; +} |