import gdb-19990422 snapshot

This commit is contained in:
Stan Shebs 1999-04-27 01:26:45 +00:00
parent 7a292a7adf
commit e49d4fa61a
8 changed files with 1806 additions and 0 deletions

33
gdb/MAINTAINERS Normal file
View File

@ -0,0 +1,33 @@
d10v target Andrew Cagney cagney@cygnus.com
d30v target Andrew Cagney cagney@cygnus.com
mips target Andrew Cagney cagney@cygnus.com
powerpc target Andrew Cagney cagney@cygnus.com
generic arch support Andrew Cagney cagney@cygnus.com
target vector Andrew Cagney cagney@cygnus.com
remote.c Andrew Cagney cagney@cygnus.com
djgpp native DJ Delorie dj@cygnus.com
win32 host & native Chris Faylor cgf@cygnus.com
main (main.c, top.c) Elena Zannoni ezannoni@cygnus.com
readline Elena Zannoni ezannoni@cygnus.com
arm target Elena Zannoni ezannoni@cygnus.com
command interpreter Fernando Nasser fnasser@cygnus.com
generic symtabs Jim Blandy jimb@cygnus.com
dwarf readers Jim Blandy jimb@cygnus.com
elf reader Jim Blandy jimb@cygnus.com
stabs reader Jim Blandy jimb@cygnus.com
x86 linux native Jim Blandy jimb@cygnus.com
Scheme support Jim Blandy jimb@cygnus.com
m32r target Michael Snyder msnyder@cygnus.com
tracing Michael Snyder msnyder@cygnus.com
threads Michael Snyder msnyder@cygnus.com
breakpoint.c Michael Snyder msnyder@cygnus.com
macos host & native Stan Shebs shebs@cygnus.com
sds protocol Stan Shebs shebs@cygnus.com
rdi/adp protocol Stan Shebs shebs@cygnus.com
gdbserver Stan Shebs shebs@cygnus.com
documentation Stan Shebs shebs@cygnus.com
testsuite Stan Shebs shebs@cygnus.com
language support David Taylor taylor@cygnus.com
expression eval David Taylor taylor@cygnus.com
defs.h David Taylor taylor@cygnus.com
utils.c David Taylor taylor@cygnus.com

3
gdb/config/i386/go32.mt Normal file
View File

@ -0,0 +1,3 @@
# Target: Intel 386 running DJGPP
TDEPFILES= i386-tdep.o i387-tdep.o
TM_FILE= tm-go32.h

57
gdb/config/i386/nm-go32.h Normal file
View File

@ -0,0 +1,57 @@
/* Native definitions for Intel x86 running DJGPP.
Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
This file is part of GDB.
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#define NO_PTRACE_H
#include "i386/nm-i386v.h"
#define TARGET_HAS_HARDWARE_WATCHPOINTS
#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(type, cnt, ot) 1
/* After a watchpoint trap, the PC points to the instruction after the
one that caused the trap. Therefore we don't need to step over it.
But we do need to reset the status register to avoid another trap. */
#define HAVE_CONTINUABLE_WATCHPOINT
#define STOPPED_BY_WATCHPOINT(W) \
go32_stopped_by_watchpoint (inferior_pid)
/* Use these macros for watchpoint insertion/removal. */
#define target_insert_watchpoint(addr, len, type) \
go32_insert_watchpoint (inferior_pid, addr, len, 2)
#define target_remove_watchpoint(addr, len, type) \
go32_remove_watchpoint (inferior_pid, addr, len)
#define target_insert_hw_breakpoint(addr, shadow) \
go32_insert_hw_breakpoint(addr, shadow)
#define target_remove_hw_breakpoint(addr, shadow) \
go32_remove_hw_breakpoint(addr, shadow)
#define DECR_PC_AFTER_HW_BREAK 0
#undef FLOAT_INFO
#define FLOAT_INFO { i386_go32_float_info (); }
extern void i386_go32_float_info (void);

212
gdb/config/i386/tm-go32.h Normal file
View File

@ -0,0 +1,212 @@
/* Target-dependent definitions for Intel x86 running DJGPP.
Copyright 1995, 1996, 1997 Free Software Foundation, Inc.
This file is part of GDB.
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "i386/tm-i386v.h"
/* Number of machine registers. */
#undef NUM_FREGS
#define NUM_FREGS 15
#undef NUM_REGS
#define NUM_REGS (16+NUM_FREGS)
/* Initializer for an array of names of registers. There should be
NUM_REGS strings in this initializer. */
/* The order of the first 8 registers must match the compiler's
numbering scheme (which is the same as the 386 scheme). */
#undef REGISTER_NAMES
#define REGISTER_NAMES { "eax", "ecx", "edx", "ebx", \
"esp", "ebp", "esi", "edi", \
"eip", "eflags","cs", "ss", \
"ds", "es", "fs", "gs", \
"st0", "st1", "st2", "st3", \
"st4", "st5", "st6", "st7", \
"fctrl","fstat", "ftag", "fcs", \
"fopsel","fip", "fopoff" }
#undef FP_REGNUM
#define FP_REGNUM 5 /* (ebp) Contains addr of stack frame */
#undef SP_REGNUM
#define SP_REGNUM 4 /* (usp) Contains address of top of stack */
#undef PS_REGNUM
#define PS_REGNUM 9 /* (ps) Contains processor status */
#undef PC_REGNUM
#define PC_REGNUM 8 /* (eip) Contains program counter */
#undef FP0_REGNUM
#define FP0_REGNUM 16 /* Floating point register 0 */
#undef FPC_REGNUM
#define FPC_REGNUM 24 /* 80387 control register */
#undef FPCWD_REGNUM
#define FPCWD_REGNUM FPC_REGNUM
#undef FPSWD_REGNUM
#define FPSWD_REGNUM 25 /* 80387 status register */
#undef FPTWD_REGNUM
#define FPTWD_REGNUM 26 /* 80387 tag register */
#undef FPIPO_REGNUM
#define FPIPO_REGNUM 29 /* 80387 instruction pointer offset reg */
#undef FPIPS_REGNUM
#define FPIPS_REGNUM 27 /* 80387 instruction pointer selector reg */
#undef FPOOS_REGNUM
#define FPOOS_REGNUM 30 /* 80387 operand pointer offset reg */
#undef FPOPS_REGNUM
#define FPOPS_REGNUM 28 /* 80387 operand pointer selector reg */
/* Total amount of space needed to store our copies of the machine's
register state, the array `registers'. */
#undef REGISTER_BYTES
#define REGISTER_BYTES (10*4 + 6*2 + 8*10 + 5*2 + 2*4)
/* Index within `registers' of the first byte of the space for
register N. */
#undef REGISTER_BYTE
#define REGBYTE_0 0
#define REGBYTE_10 (REGBYTE_0+10*4)
#define REGBYTE_16 (REGBYTE_10+6*2)
#define REGBYTE_24 (REGBYTE_16+8*10)
#define REGBYTE_29 (REGBYTE_24+5*2)
#define REGISTER_BYTE(N) (((N) < 10) ? (N) * 4 : \
(N) < 16 ? REGBYTE_10 +((N) - 10) * 2 : \
(N) < 24 ? REGBYTE_16 +((N) - 16) * 10 : \
(N) < 29 ? REGBYTE_24 +((N) - 24) * 2 : \
REGBYTE_29 + ((N) - 29) * 4)
/* Number of bytes of storage in the actual machine representation
for register N. */
#undef REGISTER_RAW_SIZE
#define REGISTER_RAW_SIZE(N) ((N) < 10 ? 4 : (N) < 16 ? 2 : (N) < 24 ? 10 : \
(N) < 29 ? 2 : 4)
/* Number of bytes of storage in the program's representation
for register N. */
#undef REGISTER_VIRTUAL_SIZE
#define REGISTER_VIRTUAL_SIZE(N) REGISTER_RAW_SIZE(N)
/* Largest value REGISTER_RAW_SIZE can have. */
#undef MAX_REGISTER_RAW_SIZE
#define MAX_REGISTER_RAW_SIZE 10
/* Largest value REGISTER_VIRTUAL_SIZE can have. */
#undef MAX_REGISTER_VIRTUAL_SIZE
#define MAX_REGISTER_VIRTUAL_SIZE 10
/* Nonzero if register N requires conversion
from raw format to virtual format. */
#undef REGISTER_CONVERTIBLE
#define REGISTER_CONVERTIBLE(N) ((N) < FP0_REGNUM ? 0 :\
(N) < FPC_REGNUM ? 1 : 0)
/* The host and target are i386 machines and the compiler supports
long doubles. Long doubles on the host therefore have the same
layout as a 387 FPU stack register. */
#if defined(HAVE_LONG_DOUBLE) && defined(HOST_I386)
#undef LD_I387
#define LD_I387
#endif
/* Allow floating point numbers to be specified by a raw long double
10 hex bytes number, e.g. 1.0 can be input as
0x3fff8000000000000000 */
#ifdef LD_I387
#define HEX_LONG_DOUBLE_INPUT(base,p,len,target) \
((base) == 16 && (len) == 20 \
&& i387_hex_long_double_input ((p), (target)))
#endif
extern int i387_hex_long_double_input (char *p, long double *putithere);
#undef REGISTER_CONVERT_TO_VIRTUAL
#ifdef LD_I387
#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,TYPE,FROM,TO) \
{ \
if (TYPE == REGISTER_VIRTUAL_TYPE (REGNUM)) \
{ \
memcpy (TO, FROM, TYPE_LENGTH (TYPE)); \
} \
else \
{ \
long double val = *((long double *)FROM); \
store_floating ((TO), TYPE_LENGTH (TYPE), val); \
} \
}
#else
/* Convert data from raw format for register REGNUM in buffer FROM to
virtual format with type TYPE in buffer TO. */
#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,TYPE,FROM,TO) \
{ \
double val; \
i387_to_double ((FROM), (char *)&val); \
store_floating ((TO), TYPE_LENGTH (TYPE), val); \
}
#endif
extern void i387_to_double PARAMS ((char *, char *));
#undef REGISTER_CONVERT_TO_RAW
#ifdef LD_I387
#define REGISTER_CONVERT_TO_RAW(TYPE,REGNUM,FROM,TO) \
{ \
if (TYPE == REGISTER_VIRTUAL_TYPE (REGNUM)) \
{ \
memcpy (TO, FROM, TYPE_LENGTH (TYPE)); \
} \
else \
{ \
long double val = extract_floating ((FROM), TYPE_LENGTH (TYPE)); \
*((long double *)TO) = val; \
} \
}
#else
#define REGISTER_CONVERT_TO_RAW(TYPE,REGNUM,FROM,TO) \
{ \
double val = extract_floating ((FROM), TYPE_LENGTH (TYPE)); \
double_to_i387((char *)&val, (TO)); \
}
#endif
extern void double_to_i387 PARAMS ((char *, char *));
/* Return the GDB type object for the "standard" data type of data in
register N. */
#undef REGISTER_VIRTUAL_TYPE
#ifdef LD_I387
#define REGISTER_VIRTUAL_TYPE(N) \
((N < FP0_REGNUM) ? builtin_type_int : \
(N < FPC_REGNUM) ? builtin_type_long_double : builtin_type_int)
#else
#define REGISTER_VIRTUAL_TYPE(N) \
((N < FP0_REGNUM) ? builtin_type_int : \
(N < FPC_REGNUM) ? builtin_type_double : builtin_type_int)
#endif
#undef TARGET_LONG_DOUBLE_BIT
#define TARGET_LONG_DOUBLE_BIT 96
#define NAMES_HAVE_UNDERSCORE

View File

@ -0,0 +1,7 @@
# Target: TI TMS320C80 (MVP) processor
TDEPFILES= tic80-tdep.o
TM_FILE= tm-tic80.h
SIM_OBS = remote-sim.o
SIM = ../sim/tic80/libsim.a
GDBSERVER_DEPFILES= low-sim.o
GDBSERVER_LIBS = ../../sim/tic80/libsim.a ../../bfd/libbfd.a ../../libiberty/libiberty.a -lm

257
gdb/config/tic80/tm-tic80.h Normal file
View File

@ -0,0 +1,257 @@
/* Parameters for execution on a TI TMS320C80 (MVP) processor.
Copyright 1997
Free Software Foundation, Inc.
This file is part of GDB.
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef TM_TIC80_H
#define TM_TIC80_H
#ifdef __STDC__ /* Forward declare structs used in prototypes */
struct frame_info;
struct type;
struct value;
struct symbol;
struct frame_saved_regs;
#endif
#define TARGET_BYTE_ORDER LITTLE_ENDIAN
/* Define this if the C compiler puts an underscore at the front
of external names before giving them to the linker. */
#define NAMES_HAVE_UNDERSCORE
#define NUM_REGS 38
#define REGISTER_NAMES \
{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", \
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", \
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", \
"pc", "npc", \
"a0", "a1", "a2", "a3", \
}
/* Various dedicated register numbers
FIXME: Shadow updates in sim/tic80/sim-calls.c */
#define SP_REGNUM 1 /* Contains address of top of stack */
#define ARG0_REGNUM 2 /* Contains argument 1 (r3 has high word) */
#define RET_REGNUM 2 /* Contains function return value */
#define ARGLAST_REGNUM 12 /* Contains argument 6 (r13 has high word) */
#define FP_REGNUM 30 /* Contains address of executing stack frame */
#define LR_REGNUM 31 /* Contains address of caller (link register) */
#define PC_REGNUM 32 /* Contains program counter (FIXME?) */
#define NPC_REGNUM 33 /* Contains the next program counter (FIXME?) */
#define A0_REGNUM 34 /* Accumulator register 0 */
#define A3_REGNUM 37 /* Accumulator register 1 */
#define R0_REGNUM 0 /* General Purpose Register 0 - for sim */
#define Rn_REGNUM 31 /* Last General Purpose Register - for sim */
#define An_REGNUM A3_REGNUM /* Last Accumulator register - for sim */
/* Total amount of space needed to store our copies of the machine's
register state, the array `registers'. */
#define REGISTER_BYTES (((NUM_REGS - 4) * 4) + (4 * 8))
/* Index within `registers' of the first byte of the space for
register N. */
#define REGISTER_BYTE(N) \
(((N) >= A0_REGNUM) ? (((N) - A0_REGNUM) * 8 + A0_REGNUM * 4) : ((N) * 4))
/* Most registers are 4 bytes */
#define REGISTER_SIZE 4
/* Some registers are 8 bytes. */
#define REGISTER_RAW_SIZE(N) \
(((N) >= A0_REGNUM) ? 8 : 4)
/* Largest value REGISTER_RAW_SIZE can have. */
#define MAX_REGISTER_RAW_SIZE (8)
/* All regs are 4 bytes. */
#define REGISTER_VIRTUAL_SIZE(N) (REGISTER_RAW_SIZE(N))
/* Largest value REGISTER_VIRTUAL_SIZE can have. */
#define MAX_REGISTER_VIRTUAL_SIZE (MAX_REGISTER_RAW_SIZE)
/* Return the GDB type object for the "standard" data type
of data in register N. */
#define REGISTER_VIRTUAL_TYPE(N) /* FIXME? */ \
(((N) >= A0_REGNUM) ? builtin_type_float : builtin_type_int)
/* Offset from address of function to start of its code.
Zero on most machines. */
#define FUNCTION_START_OFFSET 0
/* Stack grows downward. */
#define INNER_THAN(lhs,rhs) ((lhs) < (rhs))
/* Sequence of bytes for breakpoint instruction.
This is padded out to the size of a machine word. */
#define BREAKPOINT {0x49, 0x80, 0x00, 0x00} /* FIXME! */
/* Amount PC must be decremented by after a breakpoint.
This is often the number of bytes in BREAKPOINT
but not always. */
#define DECR_PC_AFTER_BREAK 0 /* FIXME! */
/* Discard from the stack the innermost frame, restoring all registers. */
#define POP_FRAME tic80_pop_frame(get_current_frame ())
extern struct frame_info *tic80_pop_frame PARAMS ((struct frame_info *frame));
/* Return number of bytes at start of arglist that are not really args. */
#define FRAME_ARGS_SKIP 0
/* Set VAL to the number of args passed to frame described by FI.
Can set VAL to -1, meaning no way to tell. */
/* We can't tell how many args there are */
#define FRAME_NUM_ARGS(val,fi) (val = -1)
#define FRAME_ARGS_SKIP 0
#define FRAME_ARGS_ADDRESS(fi) (fi)->frame
#define FRAME_LOCALS_ADDRESS(fi) (fi)->frame
/* Define other aspects of the stack frame.
We keep the offsets of all saved registers, 'cause we need 'em a lot!
We also keep the current size of the stack frame, and the offset of
the frame pointer from the stack pointer (for frameless functions, and
when we're still in the prologue of a function with a frame) */
#define EXTRA_FRAME_INFO \
struct frame_saved_regs fsr; \
int framesize; \
int frameoffset; \
int framereg;
extern void tic80_init_extra_frame_info PARAMS ((struct frame_info *fi));
#define INIT_EXTRA_FRAME_INFO(fromleaf, fi) tic80_init_extra_frame_info (fi)
#define INIT_FRAME_PC /* Not necessary */
/* Put here the code to store, into a struct frame_saved_regs,
the addresses of the saved registers of frame described by FRAME_INFO.
This includes special registers such as pc and fp saved in special
ways in the stack frame. sp is even more special:
the address we return for it IS the sp for the next frame. */
#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \
tic80_frame_find_saved_regs(frame_info, &(frame_saved_regs))
extern void tic80_frame_find_saved_regs PARAMS ((struct frame_info *, struct frame_saved_regs *));
/* Advance PC across any function entry prologue instructions
to reach some "real" code. */
#define SKIP_PROLOGUE(pc) { (pc) = tic80_skip_prologue (pc); }
extern CORE_ADDR tic80_skip_prologue PARAMS ((CORE_ADDR pc));
/* Immediately after a function call, return the saved pc.
Can't always go through the frames for this because on some machines
the new frame is not set up until the new function executes
some instructions. */
#define SAVED_PC_AFTER_CALL(frame) read_register (LR_REGNUM)
/* Describe the pointer in each stack frame to the previous stack frame
(its caller). */
/* FRAME_CHAIN takes a frame's nominal address
and produces the frame's chain-pointer. */
#define FRAME_CHAIN(thisframe) (CORE_ADDR) tic80_frame_chain (thisframe)
extern CORE_ADDR tic80_frame_chain PARAMS ((struct frame_info *));
#define FRAME_SAVED_PC(FRAME) tic80_frame_saved_pc (FRAME)
extern CORE_ADDR tic80_frame_saved_pc PARAMS ((struct frame_info *));
/* Store the address of the place in which to copy the structure the
subroutine will return. This is called from call_function.
We store structs through a pointer passed in R2 */
#define STORE_STRUCT_RETURN(STRUCT_ADDR, SP) \
write_register (ARG0_REGNUM, STRUCT_ADDR)
/* Extract from an array REGBUF containing the (raw) register state
a function return value of type TYPE, and copy that, in virtual format,
into VALBUF. */
#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
memcpy ((VALBUF), \
(char *)(REGBUF) + REGISTER_BYTE (RET_REGNUM) + \
((TYPE_LENGTH (TYPE) > 4 ? 8 : 4) - TYPE_LENGTH (TYPE)), \
TYPE_LENGTH (TYPE))
/* Write into appropriate registers a function return value
of type TYPE, given in virtual format. */
#define STORE_RETURN_VALUE(TYPE,VALBUF) \
write_register_bytes(REGISTER_BYTE (RET_REGNUM) + \
((TYPE_LENGTH (TYPE) > 4 ? 8:4) - TYPE_LENGTH (TYPE)),\
(VALBUF), TYPE_LENGTH (TYPE));
/* PUSH_ARGUMENTS */
extern CORE_ADDR tic80_push_arguments PARAMS ((int nargs,
struct value **args,
CORE_ADDR sp,
unsigned char struct_return,
CORE_ADDR struct_addr));
#define PUSH_ARGUMENTS(NARGS, ARGS, SP, STRUCT_RETURN, STRUCT_ADDR) \
(SP) = tic80_push_arguments (NARGS, ARGS, SP, STRUCT_RETURN, STRUCT_ADDR)
/* PUSH_RETURN_ADDRESS */
extern CORE_ADDR tic80_push_return_address PARAMS ((CORE_ADDR, CORE_ADDR));
#define PUSH_RETURN_ADDRESS(PC, SP) tic80_push_return_address (PC, SP)
/* override the standard get_saved_register function with
one that takes account of generic CALL_DUMMY frames */
#define GET_SAVED_REGISTER(raw_buffer, optimized, addrp, frame, regnum, lval) \
generic_get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval)
#define USE_GENERIC_DUMMY_FRAMES 1
#define CALL_DUMMY {0}
#define CALL_DUMMY_LENGTH (0)
#define CALL_DUMMY_START_OFFSET (0)
#define CALL_DUMMY_BREAKPOINT_OFFSET (0)
#define FIX_CALL_DUMMY(DUMMY1, STARTADDR, FUNADDR, NARGS, ARGS, TYPE, GCCP)
#define CALL_DUMMY_LOCATION AT_ENTRY_POINT
#define CALL_DUMMY_ADDRESS() entry_point_address ()
/* generic dummy frame stuff */
#define PUSH_DUMMY_FRAME generic_push_dummy_frame ()
#define PC_IN_CALL_DUMMY(PC, SP, FP) generic_pc_in_call_dummy (PC, SP, FP)
#endif /* TM_TIC80_H */

754
gdb/go32-nat.c Normal file
View File

@ -0,0 +1,754 @@
/* Native debugging support for Intel x86 running DJGPP.
Copyright 1997, 1999 Free Software Foundation, Inc.
Written by Robert Hoehne.
This file is part of GDB.
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <fcntl.h>
#include "defs.h"
#include "frame.h" /* required by inferior.h */
#include "inferior.h"
#include "target.h"
#include "wait.h"
#include "gdbcore.h"
#include "command.h"
#include "floatformat.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <debug/v2load.h>
#include <debug/dbgcom.h>
extern void _initialize_go32_nat (void);
struct env387
{
unsigned short control;
unsigned short r0;
unsigned short status;
unsigned short r1;
unsigned short tag;
unsigned short r2;
unsigned long eip;
unsigned short code_seg;
unsigned short opcode;
unsigned long operand;
unsigned short operand_seg;
unsigned short r3;
unsigned char regs[8][10];
};
extern char **environ;
#define SOME_PID 42
/* FIXME add decls of all static functions here */
static int prog_has_started = 0;
static void
print_387_status (unsigned short status, struct env387 *ep)
{
int i;
int bothstatus;
int top;
int fpreg;
bothstatus = ((status != 0) && (ep->status != 0));
if (status != 0)
{
if (bothstatus)
printf_unfiltered ("u: ");
print_387_status_word (status);
}
if (ep->status != 0)
{
if (bothstatus)
printf_unfiltered ("e: ");
print_387_status_word (ep->status);
}
print_387_control_word (ep->control & 0xffff);
printf_unfiltered ("last exception: ");
printf_unfiltered ("opcode %s; ", local_hex_string (ep->opcode));
printf_unfiltered ("pc %s:", local_hex_string (ep->code_seg));
printf_unfiltered ("%s; ", local_hex_string (ep->eip));
printf_unfiltered ("operand %s", local_hex_string (ep->operand_seg));
printf_unfiltered (":%s\n", local_hex_string (ep->operand));
top = (ep->status >> 11) & 7;
printf_unfiltered ("regno tag msb lsb value\n");
for (fpreg = 0; fpreg < 8; fpreg++)
{
long double val;
printf_unfiltered ("%s %d: ", fpreg == top ? "=>" : " ", fpreg);
switch ((ep->tag >> (fpreg * 2)) & 3)
{
case 0:
printf_unfiltered ("valid ");
break;
case 1:
printf_unfiltered ("zero ");
break;
case 2:
printf_unfiltered ("trap ");
break;
case 3:
printf_unfiltered ("empty ");
break;
}
for (i = 0; i < 8; i++)
printf_unfiltered ("%02x", ep->regs[fpreg][i]);
REGISTER_CONVERT_TO_VIRTUAL (FP0_REGNUM + fpreg, builtin_type_long_double,
&ep->regs[fpreg], &val);
printf_unfiltered (" %LG\n", val);
}
}
void
i386_go32_float_info (void)
{
print_387_status (0, (struct env387 *) &npx);
}
#define r_ofs(x) ((int)(&(((TSS *)0)->x)))
static struct
{
int tss_ofs;
int size;
}
regno_mapping[] =
{
r_ofs (tss_eax), 4,
r_ofs (tss_ecx), 4,
r_ofs (tss_edx), 4,
r_ofs (tss_ebx), 4,
r_ofs (tss_esp), 4,
r_ofs (tss_ebp), 4,
r_ofs (tss_esi), 4,
r_ofs (tss_edi), 4,
r_ofs (tss_eip), 4,
r_ofs (tss_eflags), 4,
r_ofs (tss_cs), 2,
r_ofs (tss_ss), 2,
r_ofs (tss_ds), 2,
r_ofs (tss_es), 2,
r_ofs (tss_fs), 2,
r_ofs (tss_gs), 2,
0, 10,
1, 10,
2, 10,
3, 10,
4, 10,
5, 10,
6, 10,
7, 10,
0, 2,
4, 2,
8, 2,
12, 4,
16, 2,
20, 4,
24, 2
};
static struct
{
int go32_sig;
int gdb_sig;
}
sig_map[] =
{
0, TARGET_SIGNAL_FPE,
1, TARGET_SIGNAL_TRAP,
2, TARGET_SIGNAL_UNKNOWN,
3, TARGET_SIGNAL_TRAP,
4, TARGET_SIGNAL_FPE,
5, TARGET_SIGNAL_SEGV,
6, TARGET_SIGNAL_ILL,
7, TARGET_SIGNAL_FPE,
8, TARGET_SIGNAL_SEGV,
9, TARGET_SIGNAL_SEGV,
10, TARGET_SIGNAL_BUS,
11, TARGET_SIGNAL_SEGV,
12, TARGET_SIGNAL_SEGV,
13, TARGET_SIGNAL_ABRT,
14, TARGET_SIGNAL_SEGV,
16, TARGET_SIGNAL_FPE,
31, TARGET_SIGNAL_ILL,
0x75, TARGET_SIGNAL_FPE,
0x79, TARGET_SIGNAL_INT,
0x1b, TARGET_SIGNAL_INT,
-1, -1
};
static void
go32_open (char *name, int from_tty)
{
printf_unfiltered ("Use the `run' command to run go32 programs\n");
}
static void
go32_close (int quitting)
{
}
static void
go32_attach (char *args, int from_tty)
{
printf_unfiltered ("Use the `run' command to run go32 programs\n");
}
static void
go32_detach (char *args, int from_tty)
{
}
static int resume_is_step;
static void
go32_resume (int pid, int step, enum target_signal siggnal)
{
resume_is_step = step;
}
static int
go32_wait (int pid, struct target_waitstatus *status)
{
int i;
if (resume_is_step)
a_tss.tss_eflags |= 0x0100;
else
a_tss.tss_eflags &= 0xfeff;
run_child ();
if (a_tss.tss_irqn == 0x21)
{
status->kind = TARGET_WAITKIND_EXITED;
status->value.integer = a_tss.tss_eax & 0xff;
}
else
{
status->value.sig = TARGET_SIGNAL_UNKNOWN;
status->kind = TARGET_WAITKIND_STOPPED;
for (i = 0; sig_map[i].go32_sig != -1; i++)
{
if (a_tss.tss_irqn == sig_map[i].go32_sig)
{
if ((status->value.sig = sig_map[i].gdb_sig) !=
TARGET_SIGNAL_TRAP)
status->kind = TARGET_WAITKIND_SIGNALLED;
break;
}
}
}
return SOME_PID;
}
static void
go32_fetch_registers (int regno)
{
/*JHW*/
int end_reg = regno + 1; /* just one reg initially */
if (regno < 0) /* do the all registers */
{
regno = 0; /* start at first register */
/* # regs in table */
end_reg = sizeof (regno_mapping) / sizeof (regno_mapping[0]);
}
for (; regno < end_reg; regno++)
{
if (regno < 16)
supply_register (regno,
(char *) &a_tss + regno_mapping[regno].tss_ofs);
else if (regno < 24)
supply_register (regno,
(char *) &npx.reg[regno_mapping[regno].tss_ofs]);
else if (regno < 31)
supply_register (regno,
(char *) &npx.reg + regno_mapping[regno].tss_ofs);
else
{
printf_unfiltered ("Invalid register in go32_fetch_register(%d)",
regno);
exit (1);
}
}
}
static void
store_register (int regno)
{
void *rp;
void *v = (void *) &registers[REGISTER_BYTE (regno)];
if (regno < 16)
rp = (char *) &a_tss + regno_mapping[regno].tss_ofs;
else if (regno < 24)
rp = (char *) &npx.reg[regno_mapping[regno].tss_ofs];
else if (regno > 31)
rp = (char *) &npx + regno_mapping[regno].tss_ofs;
else
{
printf_unfiltered ("Invalid register in store_register(%d)", regno);
exit (1);
}
memcpy (rp, v, regno_mapping[regno].size);
}
static void
go32_store_registers (int regno)
{
int r;
if (regno >= 0)
store_register (regno);
else
{
for (r = 0; r < sizeof (regno_mapping) / sizeof (regno_mapping[0]); r++)
store_register (r);
}
}
static void
go32_prepare_to_store (void)
{
}
static int
go32_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
struct target_ops *target)
{
if (write)
{
if (write_child (memaddr, myaddr, len))
{
return 0;
}
else
{
return len;
}
}
else
{
if (read_child (memaddr, myaddr, len))
{
return 0;
}
else
{
return len;
}
}
}
static void
go32_files_info (struct target_ops *target)
{
printf_unfiltered ("You are running a DJGPP V2 program\n");
}
static void
go32_stop (void)
{
normal_stop ();
cleanup_client ();
inferior_pid = 0;
prog_has_started = 0;
}
static void
go32_kill_inferior (void)
{
go32_stop ();
unpush_target (&go32_ops);
}
static void
go32_create_inferior (char *exec_file, char *args, char **env)
{
jmp_buf start_state;
char *cmdline;
char **env_save = environ;
if (prog_has_started)
{
go32_kill_inferior ();
}
cmdline = (char *) alloca (strlen (args) + 4);
cmdline[0] = strlen (args);
strcpy (cmdline + 1, args);
cmdline[strlen (args) + 1] = 13;
environ = env;
if (v2loadimage (exec_file, cmdline, start_state))
{
environ = env_save;
printf_unfiltered ("Load failed for image %s\n", exec_file);
exit (1);
}
environ = env_save;
edi_init (start_state);
inferior_pid = SOME_PID;
push_target (&go32_ops);
clear_proceed_status ();
insert_breakpoints ();
proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0);
}
static void
go32_mourn_inferior (void)
{
go32_kill_inferior ();
generic_mourn_inferior ();
}
static int
go32_can_run (void)
{
return 1;
}
static void
ignore (void)
{
}
static void
ignore2 (char *a, int b)
{
}
/* Hardware watchpoint support. */
#define DR_STATUS 6
#define DR_CONTROL 7
#define DR_ENABLE_SIZE 2
#define DR_LOCAL_ENABLE_SHIFT 0
#define DR_GLOBAL_ENABLE_SHIFT 1
#define DR_LOCAL_SLOWDOWN 0x100
#define DR_GLOBAL_SLOWDOWN 0x200
#define DR_CONTROL_SHIFT 16
#define DR_CONTROL_SIZE 4
#define DR_RW_READ 0x3
#define DR_RW_WRITE 0x1
#define DR_CONTROL_MASK 0xf
#define DR_ENABLE_MASK 0x3
#define DR_LEN_1 0x0
#define DR_LEN_2 0x4
#define DR_LEN_4 0xc
#define D_REGS edi.dr
#define CONTROL D_REGS[DR_CONTROL]
#define STATUS D_REGS[DR_STATUS]
#define IS_REG_FREE(index) \
(!(CONTROL & (3 << (DR_ENABLE_SIZE * index))))
#define LOCAL_ENABLE_REG(index) \
(CONTROL |= (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * index)))
#define GLOBAL_ENABLE_REG(index) \
(CONTROL |= (1 << (DR_GLOBAL_ENABLE_SHIFT + DR_ENABLE_SIZE * index)))
#define DISABLE_REG(index) \
(CONTROL &= ~(3 << (DR_ENABLE_SIZE * index)))
#define SET_LOCAL_EXACT() \
(CONTROL |= DR_LOCAL_SLOWDOWN)
#define SET_GLOBAL_EXACT() \
(CONTROL |= DR_GLOBAL_SLOWDOWN)
#define SET_BREAK(index,address) \
do {\
CONTROL &= ~(DR_CONTROL_MASK << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * index));\
D_REGS[index] = address;\
} while(0)
#define SET_WATCH(index,address,rw,len) \
do {\
SET_BREAK(index,address);\
CONTROL |= (len | rw) << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * index);\
} while (0)
#define WATCH_HIT(index) \
(\
(STATUS & (1 << index)) && \
(CONTROL & (DR_CONTROL_MASK << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * index)))\
)
#if 0 /* use debugging macro */
#define SHOW_DR(text) \
do { \
fprintf(stderr,"%08x %08x ",edi.dr[7],edi.dr[6]); \
fprintf(stderr,"%08x %08x ",edi.dr[0],edi.dr[1]); \
fprintf(stderr,"%08x %08x ",edi.dr[2],edi.dr[3]); \
fprintf(stderr,"(%s)\n",#text); \
} while (0)
#else
#define SHOW_DR(text) do {} while (0)
#endif
static int go32_insert_aligned_watchpoint (int pid, CORE_ADDR waddr,
CORE_ADDR addr, int len, int rw);
static int go32_insert_nonaligned_watchpoint (int pid, CORE_ADDR waddr,
CORE_ADDR addr, int len, int rw);
/* Insert a watchpoint. */
int
go32_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw)
{
int ret = go32_insert_aligned_watchpoint (pid, addr, addr, len, rw);
SHOW_DR (insert_watch);
return ret;
}
static int
go32_insert_aligned_watchpoint (int pid, CORE_ADDR waddr, CORE_ADDR addr,
int len, int rw)
{
int i;
int read_write_bits, len_bits;
/* Look for a free debug register. */
for (i = 0; i <= 3; i++)
{
if (IS_REG_FREE (i))
break;
}
/* No more debug registers! */
if (i > 3)
return -1;
read_write_bits = ((rw & 1) ? DR_RW_READ : 0) | ((rw & 2) ? DR_RW_WRITE : 0);
if (len == 1)
len_bits = DR_LEN_1;
else if (len == 2)
{
if (addr % 2)
return go32_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
len_bits = DR_LEN_2;
}
else if (len == 4)
{
if (addr % 4)
return go32_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
len_bits = DR_LEN_4;
}
else
return go32_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
SET_WATCH (i, addr, read_write_bits, len_bits);
LOCAL_ENABLE_REG (i);
SET_LOCAL_EXACT ();
}
static int
go32_insert_nonaligned_watchpoint (int pid, CORE_ADDR waddr, CORE_ADDR addr,
int len, int rw)
{
int align;
int size;
int rv = 0;
static int size_try_array[16] =
{
1, 1, 1, 1, /* trying size one */
2, 1, 2, 1, /* trying size two */
2, 1, 2, 1, /* trying size three */
4, 1, 2, 1 /* trying size four */
};
while (len > 0)
{
align = addr % 4;
/* Four is the maximum length for 386. */
size = (len > 4) ? 3 : len - 1;
size = size_try_array[size * 4 + align];
rv = go32_insert_aligned_watchpoint (pid, waddr, addr, size, rw);
if (rv)
{
go32_remove_watchpoint (pid, waddr, size);
return rv;
}
addr += size;
len -= size;
}
return rv;
}
/* Remove a watchpoint. */
int
go32_remove_watchpoint (int pid, CORE_ADDR addr, int len)
{
int i;
for (i = 0; i <= 3; i++)
{
if (D_REGS[i] == addr)
{
DISABLE_REG (i);
}
}
SHOW_DR (remove_watch);
return 0;
}
/* Check if stopped by a watchpoint. */
CORE_ADDR
go32_stopped_by_watchpoint (int pid)
{
int i, ret = 0;
int status;
status = edi.dr[DR_STATUS];
SHOW_DR (stopped_by);
for (i = 0; i <= 3; i++)
{
if (WATCH_HIT (i))
{
SHOW_DR (HIT);
ret = D_REGS[i];
}
}
/* this is a hack to GDB. If we stopped at a hardware breakpoint,
the stop_pc must incremented by DECR_PC_AFTER_BREAK. I tried everything
with the DECR_PC_AFTER_HW_BREAK, but nothing works. */
/* This is probably fixed by jtc's recent patch -sts 2/19/99 */
if (STATUS && !ret)
stop_pc += DECR_PC_AFTER_BREAK;
STATUS = 0;
return ret;
}
/* Remove a breakpoint. */
int
go32_remove_hw_breakpoint (CORE_ADDR addr, CORE_ADDR shadow)
{
int i;
for (i = 0; i <= 3; i++)
{
if (D_REGS[i] == addr)
{
DISABLE_REG (i);
}
}
SHOW_DR (remove_hw);
return 0;
}
int
go32_insert_hw_breakpoint (CORE_ADDR addr, CORE_ADDR shadow)
{
int i;
int read_write_bits, len_bits;
int free_debug_register;
int register_number;
/* Look for a free debug register. */
for (i = 0; i <= 3; i++)
{
if (IS_REG_FREE (i))
break;
}
/* No more debug registers! */
if (i > 3)
return -1;
SET_BREAK (i, addr);
LOCAL_ENABLE_REG (i);
SHOW_DR (insert_hw);
return 0;
}
static struct target_ops go32_ops;
static void
init_go32_ops (void)
{
go32_ops.to_shortname = "djgpp";
go32_ops.to_longname = "djgpp target process";
go32_ops.to_doc =
"Program loaded by djgpp, when gdb is used as an external debugger";
go32_ops.to_open = go32_open;
go32_ops.to_close = go32_close;
go32_ops.to_detach = go32_detach;
go32_ops.to_resume = go32_resume;
go32_ops.to_wait = go32_wait;
go32_ops.to_fetch_registers = go32_fetch_registers;
go32_ops.to_store_registers = go32_store_registers;
go32_ops.to_prepare_to_store = go32_prepare_to_store;
go32_ops.to_xfer_memory = go32_xfer_memory;
go32_ops.to_files_info = go32_files_info;
go32_ops.to_insert_breakpoint = memory_insert_breakpoint;
go32_ops.to_remove_breakpoint = memory_remove_breakpoint;
go32_ops.to_terminal_init = ignore;
go32_ops.to_terminal_inferior = ignore;
go32_ops.to_terminal_ours_for_output = ignore;
go32_ops.to_terminal_ours = ignore;
go32_ops.to_terminal_info = ignore2;
go32_ops.to_kill = go32_kill_inferior;
go32_ops.to_create_inferior = go32_create_inferior;
go32_ops.to_mourn_inferior = go32_mourn_inferior;
go32_ops.to_can_run = go32_can_run;
go32_ops.to_stop = go32_stop;
go32_ops.to_stratum = process_stratum;
go32_ops.to_has_all_memory = 1;
go32_ops.to_has_memory = 1;
go32_ops.to_has_stack = 1;
go32_ops.to_has_registers = 1;
go32_ops.to_has_execution = 1;
go32_ops.to_magic = OPS_MAGIC;
}
void
_initialize_go32_nat (void)
{
init_go32_ops ();
add_target (&go32_ops);
}

483
gdb/tic80-tdep.c Normal file
View File

@ -0,0 +1,483 @@
/* Target-dependent code for the TI TMS320C80 (MVP) for GDB, the GNU debugger.
Copyright 1996, Free Software Foundation, Inc.
This file is part of GDB.
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "value.h"
#include "frame.h"
#include "inferior.h"
#include "obstack.h"
#include "target.h"
#include "bfd.h"
#include "gdb_string.h"
#include "gdbcore.h"
#include "symfile.h"
/* Function: frame_find_saved_regs
Return the frame_saved_regs structure for the frame.
Doesn't really work for dummy frames, but it does pass back
an empty frame_saved_regs, so I guess that's better than total failure */
void
tic80_frame_find_saved_regs (fi, regaddr)
struct frame_info *fi;
struct frame_saved_regs *regaddr;
{
memcpy (regaddr, &fi->fsr, sizeof (struct frame_saved_regs));
}
/* Function: skip_prologue
Find end of function prologue. */
CORE_ADDR
tic80_skip_prologue (pc)
CORE_ADDR pc;
{
CORE_ADDR func_addr, func_end;
struct symtab_and_line sal;
/* See what the symbol table says */
if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
{
sal = find_pc_line (func_addr, 0);
if (sal.line != 0 && sal.end < func_end)
return sal.end;
else
/* Either there's no line info, or the line after the prologue is after
the end of the function. In this case, there probably isn't a
prologue. */
return pc;
}
/* We can't find the start of this function, so there's nothing we can do. */
return pc;
}
/* Function: tic80_scan_prologue
This function decodes the target function prologue to determine:
1) the size of the stack frame
2) which registers are saved on it
3) the offsets of saved regs
4) the frame size
This information is stored in the "extra" fields of the frame_info. */
static void
tic80_scan_prologue (fi)
struct frame_info *fi;
{
struct symtab_and_line sal;
CORE_ADDR prologue_start, prologue_end, current_pc;
/* Assume there is no frame until proven otherwise. */
fi->framereg = SP_REGNUM;
fi->framesize = 0;
fi->frameoffset = 0;
/* this code essentially duplicates skip_prologue,
but we need the start address below. */
if (find_pc_partial_function (fi->pc, NULL, &prologue_start, &prologue_end))
{
sal = find_pc_line (prologue_start, 0);
if (sal.line == 0) /* no line info, use current PC */
if (prologue_start != entry_point_address ())
prologue_end = fi->pc;
else
return; /* _start has no frame or prologue */
else if (sal.end < prologue_end) /* next line begins after fn end */
prologue_end = sal.end; /* (probably means no prologue) */
}
else
/* FIXME */
prologue_end = prologue_start + 40; /* We're in the boondocks: allow for */
/* 16 pushes, an add, and "mv fp,sp" */
prologue_end = min (prologue_end, fi->pc);
/* Now search the prologue looking for instructions that set up the
frame pointer, adjust the stack pointer, and save registers. */
for (current_pc = prologue_start; current_pc < prologue_end; current_pc += 4)
{
unsigned int insn;
int regno;
int offset = 0;
insn = read_memory_unsigned_integer (current_pc, 4);
if ((insn & 0x301000) == 0x301000) /* Long immediate? */
/* FIXME - set offset for long immediate instructions */
current_pc += 4;
else
{
offset = insn & 0x7fff; /* extract 15-bit offset */
if (offset & 0x4000) /* if negative, sign-extend */
offset = -(0x8000 - offset);
}
if ((insn & 0x7fd0000) == 0x590000) /* st.{w,d} reg, xx(r1) */
{
regno = ((insn >> 27) & 0x1f);
fi->fsr.regs[regno] = offset;
if (insn & 0x8000) /* 64-bit store (st.d)? */
fi->fsr.regs[regno+1] = offset+4;
}
else if ((insn & 0xffff8000) == 0x086c8000) /* addu xx, r1, r1 */
fi->framesize = -offset;
else if ((insn & 0xffff8000) == 0xf06c8000) /* addu xx, r1, r30 */
{
fi->framereg = FP_REGNUM; /* fp is now valid */
fi->frameoffset = offset;
break; /* end of stack adjustments */
}
else if (insn == 0xf03b2001) /* addu r1, r0, r30 */
{
fi->framereg = FP_REGNUM; /* fp is now valid */
fi->frameoffset = 0;
break; /* end of stack adjustments */
}
else
/* FIXME - handle long immediate instructions */
break; /* anything else isn't prologue */
}
}
/* Function: init_extra_frame_info
This function actually figures out the frame address for a given pc and
sp. This is tricky on the c80 because we sometimes don't use an explicit
frame pointer, and the previous stack pointer isn't necessarily recorded
on the stack. The only reliable way to get this info is to
examine the prologue. */
void
tic80_init_extra_frame_info (fi)
struct frame_info *fi;
{
int reg;
if (fi->next)
fi->pc = FRAME_SAVED_PC (fi->next);
/* Because zero is a valid register offset relative to SP, we initialize
the offsets to -1 to indicate unused entries. */
for (reg = 0; reg < NUM_REGS; reg++)
fi->fsr.regs[reg] = -1;
if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
{
/* We need to setup fi->frame here because run_stack_dummy gets it wrong
by assuming it's always FP. */
fi->frame = generic_read_register_dummy (fi->pc, fi->frame, SP_REGNUM);
fi->framesize = 0;
fi->frameoffset = 0;
return;
}
else
{
tic80_scan_prologue (fi);
if (!fi->next) /* this is the innermost frame? */
fi->frame = read_register (fi->framereg);
else /* not the innermost frame */
/* If this function uses FP as the frame register, and the function
it called saved the FP, get the saved FP. */
if (fi->framereg == FP_REGNUM &&
fi->next->fsr.regs[FP_REGNUM] != (unsigned) -1)
fi->frame = read_memory_integer (fi->next->fsr.regs[FP_REGNUM], 4);
/* Convert SP-relative offsets of saved registers to real addresses. */
for (reg = 0; reg < NUM_REGS; reg++)
if (fi->fsr.regs[reg] == (unsigned) -1)
fi->fsr.regs[reg] = 0; /* unused entry */
else
fi->fsr.regs[reg] += fi->frame - fi->frameoffset;
}
}
/* Function: find_callers_reg
Find REGNUM on the stack. Otherwise, it's in an active register. One thing
we might want to do here is to check REGNUM against the clobber mask, and
somehow flag it as invalid if it isn't saved on the stack somewhere. This
would provide a graceful failure mode when trying to get the value of
caller-saves registers for an inner frame. */
CORE_ADDR
tic80_find_callers_reg (fi, regnum)
struct frame_info *fi;
int regnum;
{
for (; fi; fi = fi->next)
if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
return generic_read_register_dummy (fi->pc, fi->frame, regnum);
else if (fi->fsr.regs[regnum] != 0)
return read_memory_integer (fi->fsr.regs[regnum],
REGISTER_RAW_SIZE(regnum));
return read_register (regnum);
}
/* Function: frame_chain
Given a GDB frame, determine the address of the calling function's frame.
This will be used to create a new GDB frame struct, and then
INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC will be called for the new frame.
For c80, we save the frame size when we initialize the frame_info. */
CORE_ADDR
tic80_frame_chain (fi)
struct frame_info *fi;
{
CORE_ADDR fn_start, callers_pc, fp;
/* is this a dummy frame? */
if (PC_IN_CALL_DUMMY(fi->pc, fi->frame, fi->frame))
return fi->frame; /* dummy frame same as caller's frame */
/* is caller-of-this a dummy frame? */
callers_pc = FRAME_SAVED_PC(fi); /* find out who called us: */
fp = tic80_find_callers_reg (fi, FP_REGNUM);
if (PC_IN_CALL_DUMMY(callers_pc, fp, fp))
return fp; /* dummy frame's frame may bear no relation to ours */
if (find_pc_partial_function (fi->pc, 0, &fn_start, 0))
if (fn_start == entry_point_address ())
return 0; /* in _start fn, don't chain further */
if (fi->framereg == FP_REGNUM)
return tic80_find_callers_reg (fi, FP_REGNUM);
else
return fi->frame + fi->framesize;
}
/* Function: pop_frame
Discard from the stack the innermost frame,
restoring all saved registers. */
struct frame_info *
tic80_pop_frame (frame)
struct frame_info *frame;
{
int regnum;
if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
generic_pop_dummy_frame ();
else
{
for (regnum = 0; regnum < NUM_REGS; regnum++)
if (frame->fsr.regs[regnum] != 0)
write_register (regnum,
read_memory_integer (frame->fsr.regs[regnum], 4));
write_register (PC_REGNUM, FRAME_SAVED_PC (frame));
write_register (SP_REGNUM, read_register (FP_REGNUM));
#if 0
if (read_register (PSW_REGNUM) & 0x80)
write_register (SPU_REGNUM, read_register (SP_REGNUM));
else
write_register (SPI_REGNUM, read_register (SP_REGNUM));
#endif
}
flush_cached_frames ();
return NULL;
}
/* Function: frame_saved_pc
Find the caller of this frame. We do this by seeing if LR_REGNUM is saved
in the stack anywhere, otherwise we get it from the registers. */
CORE_ADDR
tic80_frame_saved_pc (fi)
struct frame_info *fi;
{
if (PC_IN_CALL_DUMMY(fi->pc, fi->frame, fi->frame))
return generic_read_register_dummy (fi->pc, fi->frame, PC_REGNUM);
else
return tic80_find_callers_reg (fi, LR_REGNUM);
}
/* Function: tic80_push_return_address (pc, sp)
Set up the return address for the inferior function call.
Necessary for targets that don't actually execute a JSR/BSR instruction
(ie. when using an empty CALL_DUMMY) */
CORE_ADDR
tic80_push_return_address (pc, sp)
CORE_ADDR pc;
CORE_ADDR sp;
{
write_register (LR_REGNUM, CALL_DUMMY_ADDRESS ());
return sp;
}
/* Function: push_arguments
Setup the function arguments for calling a function in the inferior.
On the TI C80 architecture, there are six register pairs (R2/R3 to R12/13)
which are dedicated for passing function arguments. Up to the first six
arguments (depending on size) may go into these registers.
The rest go on the stack.
Arguments that are smaller than 4 bytes will still take up a whole
register or a whole 32-bit word on the stack, and will be
right-justified in the register or the stack word. This includes
chars, shorts, and small aggregate types.
Arguments that are four bytes or less in size are placed in the
even-numbered register of a register pair, and the odd-numbered
register is not used.
Arguments of 8 bytes size (such as floating point doubles) are placed
in a register pair. The least significant 32-bit word is placed in
the even-numbered register, and the most significant word in the
odd-numbered register.
Aggregate types with sizes between 4 and 8 bytes are passed
entirely on the stack, and are left-justified within the
double-word (as opposed to aggregates smaller than 4 bytes
which are right-justified).
Aggregates of greater than 8 bytes are first copied onto the stack,
and then a pointer to the copy is passed in the place of the normal
argument (either in a register if available, or on the stack).
Functions that must return an aggregate type can return it in the
normal return value registers (R2 and R3) if its size is 8 bytes or
less. For larger return values, the caller must allocate space for
the callee to copy the return value to. A pointer to this space is
passed as an implicit first argument, always in R0. */
CORE_ADDR
tic80_push_arguments (nargs, args, sp, struct_return, struct_addr)
int nargs;
value_ptr *args;
CORE_ADDR sp;
unsigned char struct_return;
CORE_ADDR struct_addr;
{
int stack_offset, stack_alloc;
int argreg;
int argnum;
struct type *type;
CORE_ADDR regval;
char *val;
char valbuf[4];
int len;
int odd_sized_struct;
int is_struct;
/* first force sp to a 4-byte alignment */
sp = sp & ~3;
argreg = ARG0_REGNUM;
/* The "struct return pointer" pseudo-argument goes in R0 */
if (struct_return)
write_register (argreg++, struct_addr);
/* Now make sure there's space on the stack */
for (argnum = 0, stack_alloc = 0;
argnum < nargs; argnum++)
stack_alloc += ((TYPE_LENGTH(VALUE_TYPE(args[argnum])) + 3) & ~3);
sp -= stack_alloc; /* make room on stack for args */
/* Now load as many as possible of the first arguments into
registers, and push the rest onto the stack. There are 16 bytes
in four registers available. Loop thru args from first to last. */
argreg = ARG0_REGNUM;
for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
{
type = VALUE_TYPE (args[argnum]);
len = TYPE_LENGTH (type);
memset (valbuf, 0, sizeof (valbuf));
val = (char *) VALUE_CONTENTS (args[argnum]);
/* FIXME -- tic80 can take doubleword arguments in register pairs */
is_struct = (type->code == TYPE_CODE_STRUCT);
odd_sized_struct = 0;
if (! is_struct)
{
if (len < 4)
{ /* value gets right-justified in the register or stack word */
memcpy (valbuf + (4 - len), val, len);
val = valbuf;
}
if (len > 4 && (len & 3) != 0)
odd_sized_struct = 1; /* such structs go entirely on stack */
}
else
{
/* Structs are always passed by reference. */
write_register (argreg, sp + stack_offset);
argreg ++;
}
while (len > 0)
{
if (is_struct || argreg > ARGLAST_REGNUM || odd_sized_struct)
{ /* must go on the stack */
write_memory (sp + stack_offset, val, 4);
stack_offset += 4;
}
/* NOTE WELL!!!!! This is not an "else if" clause!!!
That's because some things get passed on the stack
AND in the registers! */
if (!is_struct && argreg <= ARGLAST_REGNUM)
{ /* there's room in a register */
regval = extract_address (val, REGISTER_RAW_SIZE(argreg));
write_register (argreg, regval);
argreg += 2; /* FIXME -- what about doubleword args? */
}
/* Store the value 4 bytes at a time. This means that things
larger than 4 bytes may go partly in registers and partly
on the stack. */
len -= REGISTER_RAW_SIZE(argreg);
val += REGISTER_RAW_SIZE(argreg);
}
}
return sp;
}
/* Function: tic80_write_sp
Because SP is really a read-only register that mirrors either SPU or SPI,
we must actually write one of those two as well, depending on PSW. */
void
tic80_write_sp (val)
CORE_ADDR val;
{
#if 0
unsigned long psw = read_register (PSW_REGNUM);
if (psw & 0x80) /* stack mode: user or interrupt */
write_register (SPU_REGNUM, val);
else
write_register (SPI_REGNUM, val);
#endif
write_register (SP_REGNUM, val);
}
void
_initialize_tic80_tdep ()
{
tm_print_insn = print_insn_tic80;
}