* [PATCH] revised m32r target
@ 2003-07-04 2:00 Kei Sakamoto
2003-07-11 7:15 ` Kei Sakamoto
0 siblings, 1 reply; 8+ messages in thread
From: Kei Sakamoto @ 2003-07-04 2:00 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 964 bytes --]
Hello,
These are the revised m32r patches. The m32r is now pure
multi-arched and contains no deprecated code.
I attached the following new files:
m32r-tdep.c
m32r-stub.c
m32r-rom.c
config/m32r/m32r.mt
I also attached a patch file for configure.tgt and toplevel
configure.
I tested the revised m32r target with sim and newlib.
=== gdb Summary ===
# of expected passes 8008
# of unexpected failures 39
# of unexpected successes 3
# of expected failures 52
# of known failures 17
# of unresolved testcases 1
# of untested testcases 3
# of unsupported tests 11
While I was testing the revised m32r target, I found several
bugs of gdb and testcases. I'll send patches for them later.
2003-07-04 Kei Sakamoto <sakamoto.kei@renesas.com>
* configure.tgt : Add m32r-*-*.
* m32r-rom.c, m32r-stub.c m32r-tdep.c,
config/m32r/m32r.mt: New files.
[-- Attachment #2: m32r.mt --]
[-- Type: application/octet-stream, Size: 139 bytes --]
# Target: Renesas m32r processor
TDEPFILES= m32r-tdep.o monitor.o m32r-rom.o dsrec.o
SIM_OBS = remote-sim.o
SIM = ../sim/m32r/libsim.a
[-- Attachment #3: m32r-tdep.c --]
[-- Type: application/octet-stream, Size: 28067 bytes --]
/* Target-dependent code for Renesas M32R, for GDB.
Copyright 1996, 1998, 1999, 2000, 2001, 2002, 2003 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 "frame.h"
#include "frame-unwind.h"
#include "frame-base.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "gdb_string.h"
#include "value.h"
#include "inferior.h"
#include "symfile.h"
#include "objfiles.h"
#include "language.h"
#include "arch-utils.h"
#include "regcache.h"
#include "trad-frame.h"
#include "gdb_assert.h"
struct gdbarch_tdep
{
/* gdbarch target dependent data here. Currently unused for M32R. */
};
/* m32r register names. */
enum
{
R0_REGNUM = 0,
R3_REGNUM = 3,
M32R_FP_REGNUM = 13,
LR_REGNUM = 14,
M32R_SP_REGNUM = 15,
PSW_REGNUM = 16,
M32R_PC_REGNUM = 21,
/* m32r calling convention. */
ARG1_REGNUM = R0_REGNUM,
ARGN_REGNUM = R3_REGNUM,
RET1_REGNUM = R0_REGNUM,
};
/* Local functions */
extern void _initialize_m32r_tdep (void);
static CORE_ADDR
m32r_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
{
/* Align to the size of an instruction (so that they can safely be
pushed onto the stack. */
return sp & ~3;
}
/* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of
EXTRACT_RETURN_VALUE? GCC_P is true if compiled with gcc
and TYPE is the type (which is known to be struct, union or array).
The m32r returns anything less than 8 bytes in size in
registers. */
static int
m32r_use_struct_convention (int gcc_p, struct type *type)
{
return (TYPE_LENGTH (type) > 8);
}
/* BREAKPOINT */
#define M32R_BE_BREAKPOINT32 {0x10, 0xf1, 0x70, 0x00}
#define M32R_LE_BREAKPOINT32 {0xf1, 0x10, 0x00, 0x70}
#define M32R_BE_BREAKPOINT16 {0x10, 0xf1}
#define M32R_LE_BREAKPOINT16 {0xf1, 0x10}
static int
m32r_memory_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
{
int val;
unsigned char *bp;
int bplen;
bplen = (addr & 3) ? 2 : 4;
/* Save the memory contents. */
val = target_read_memory (addr, contents_cache, bplen);
if (val != 0)
return val; /* return error */
/* Determine appropriate breakpoint contents and size for this address. */
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
if (((addr & 3) == 0) &&
((contents_cache[0] & 0x80) || (contents_cache[2] & 0x80)))
{
static unsigned char insn[] = M32R_BE_BREAKPOINT32;
bp = insn;
bplen = sizeof (insn);
}
else
{
static unsigned char insn[] = M32R_BE_BREAKPOINT16;
bp = insn;
bplen = sizeof (insn);
}
}
else
{ /* little-endian */
if (((addr & 3) == 0) &&
((contents_cache[1] & 0x80) || (contents_cache[3] & 0x80)))
{
static unsigned char insn[] = M32R_LE_BREAKPOINT32;
bp = insn;
bplen = sizeof (insn);
}
else
{
static unsigned char insn[] = M32R_LE_BREAKPOINT16;
bp = insn;
bplen = sizeof (insn);
}
}
/* Write the breakpoint. */
val = target_write_memory (addr, (char *) bp, bplen);
return val;
}
static int
m32r_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
{
int val;
int bplen;
/* Determine appropriate breakpoint contents and size for this address. */
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
if (((addr & 3) == 0) &&
((contents_cache[0] & 0x80) || (contents_cache[2] & 0x80)))
{
static unsigned char insn[] = M32R_BE_BREAKPOINT32;
bplen = sizeof (insn);
}
else
{
static unsigned char insn[] = M32R_BE_BREAKPOINT16;
bplen = sizeof (insn);
}
}
else
{
/* little-endian */
if (((addr & 3) == 0) &&
((contents_cache[1] & 0x80) || (contents_cache[3] & 0x80)))
{
static unsigned char insn[] = M32R_BE_BREAKPOINT32;
bplen = sizeof (insn);
}
else
{
static unsigned char insn[] = M32R_BE_BREAKPOINT16;
bplen = sizeof (insn);
}
}
/* Write contents. */
val = target_write_memory (addr, contents_cache, bplen);
return val;
}
static const unsigned char *
m32r_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
{
unsigned char *bp;
/* Determine appropriate breakpoint. */
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
if ((*pcptr & 3) == 0)
{
static unsigned char insn[] = M32R_BE_BREAKPOINT32;
bp = insn;
*lenptr = sizeof (insn);
}
else
{
static unsigned char insn[] = M32R_BE_BREAKPOINT16;
bp = insn;
*lenptr = sizeof (insn);
}
}
else
{
if ((*pcptr & 3) == 0)
{
static unsigned char insn[] = M32R_LE_BREAKPOINT32;
bp = insn;
*lenptr = sizeof (insn);
}
else
{
static unsigned char insn[] = M32R_LE_BREAKPOINT16;
bp = insn;
*lenptr = sizeof (insn);
}
}
return bp;
}
char *m32r_register_names[] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "fp", "lr", "sp",
"psw", "cbr", "spi", "spu", "bpc", "pc", "accl", "acch",
"evb"
};
static int
m32r_num_regs (void)
{
return (sizeof (m32r_register_names) / sizeof (m32r_register_names[0]));
}
static const char *
m32r_register_name (int reg_nr)
{
if (reg_nr < 0)
return NULL;
if (reg_nr >= m32r_num_regs ())
return NULL;
return m32r_register_names[reg_nr];
}
/* Return the GDB type object for the "standard" data type
of data in register N. */
static struct type *
m32r_register_type (struct gdbarch *gdbarch, int reg_nr)
{
if (reg_nr == M32R_PC_REGNUM)
return builtin_type_void_func_ptr;
else if (reg_nr == M32R_SP_REGNUM || reg_nr == M32R_FP_REGNUM)
return builtin_type_void_data_ptr;
else
return builtin_type_int32;
}
/* Write into appropriate registers a function return value
of type TYPE, given in virtual format.
Things always get returned in RET1_REGNUM, RET2_REGNUM. */
static void
m32r_store_return_value (struct type *type, struct regcache *regcache,
const void *valbuf)
{
CORE_ADDR regval;
int len = TYPE_LENGTH (type);
regval = extract_unsigned_integer (valbuf, len > 4 ? 4 : len);
regcache_cooked_write_unsigned (regcache, RET1_REGNUM, regval);
if (len > 4)
{
regval = extract_unsigned_integer (valbuf + 4, len - 4);
regcache_cooked_write_unsigned (regcache, RET1_REGNUM + 1, regval);
}
}
/* Extract from an array REGBUF containing the (raw) register state
the address in which a function should return its structure value,
as a CORE_ADDR (or an expression that can be used as one). */
static CORE_ADDR
m32r_extract_struct_value_address (struct regcache *regcache)
{
ULONGEST addr;
regcache_cooked_read_unsigned (regcache, ARG1_REGNUM, &addr);
return addr;
}
/* This is required by skip_prologue. The results of decoding a prologue
should be cached because this thrashing is getting nuts. */
static void
decode_prologue (CORE_ADDR start_pc, CORE_ADDR scan_limit,
CORE_ADDR *pl_endptr)
{
unsigned long framesize;
int insn;
int op1;
int maybe_one_more = 0;
CORE_ADDR after_prologue = 0;
CORE_ADDR after_stack_adjust = 0;
CORE_ADDR current_pc;
framesize = 0;
after_prologue = 0;
for (current_pc = start_pc; current_pc < scan_limit; current_pc += 2)
{
insn = read_memory_unsigned_integer (current_pc, 2);
/* If this is a 32 bit instruction, we dont want to examine its
immediate data as though it were an instruction */
if (current_pc & 0x02)
{
/* Clear the parallel execution bit from 16 bit instruction */
if (maybe_one_more)
{
/* The last instruction was a branch, usually terminates
the series, but if this is a parallel instruction,
it may be a stack framing instruction */
if (!(insn & 0x8000))
{
/* nope, we are really done */
break;
}
}
/* decode this instruction further */
insn &= 0x7fff;
}
else
{
if (maybe_one_more)
break; /* This isnt the one more */
if (insn & 0x8000)
{
if (current_pc == scan_limit)
scan_limit += 2; /* extend the search */
current_pc += 2; /* skip the immediate data */
if (insn == 0x8faf) /* add3 sp, sp, xxxx */
/* add 16 bit sign-extended offset */
{
framesize +=
-((short) read_memory_unsigned_integer (current_pc, 2));
}
else
{
if (((insn >> 8) == 0xe4) && /* ld24 r4, xxxxxx; sub sp, r4 */
read_memory_unsigned_integer (current_pc + 2,
2) == 0x0f24)
/* subtract 24 bit sign-extended negative-offset */
{
insn = read_memory_unsigned_integer (current_pc - 2, 4);
if (insn & 0x00800000) /* sign extend */
insn |= 0xff000000; /* negative */
else
insn &= 0x00ffffff; /* positive */
framesize += insn;
}
}
after_prologue = current_pc;
continue;
}
}
op1 = insn & 0xf000; /* isolate just the first nibble */
if ((insn & 0xf0ff) == 0x207f)
{ /* st reg, @-sp */
int regno;
framesize += 4;
regno = ((insn >> 8) & 0xf);
after_prologue = 0;
continue;
}
if ((insn >> 8) == 0x4f) /* addi sp, xx */
/* add 8 bit sign-extended offset */
{
int stack_adjust = (char) (insn & 0xff);
/* there are probably two of these stack adjustments:
1) A negative one in the prologue, and
2) A positive one in the epilogue.
We are only interested in the first one. */
if (stack_adjust < 0)
{
framesize -= stack_adjust;
after_prologue = 0;
/* A frameless function may have no "mv fp, sp".
In that case, this is the end of the prologue. */
after_stack_adjust = current_pc + 2;
}
continue;
}
if (insn == 0x1d8f)
{ /* mv fp, sp */
after_prologue = current_pc + 2;
break; /* end of stack adjustments */
}
/* Nop looks like a branch, continue explicitly */
if (insn == 0x7000)
{
after_prologue = current_pc + 2;
continue; /* nop occurs between pushes */
}
/* End of prolog if any of these are branch instructions */
if ((op1 == 0x7000) || (op1 == 0xb000) || (op1 == 0xf000))
{
after_prologue = current_pc;
maybe_one_more = 1;
continue;
}
/* Some of the branch instructions are mixed with other types */
if (op1 == 0x1000)
{
int subop = insn & 0x0ff0;
if ((subop == 0x0ec0) || (subop == 0x0fc0))
{
after_prologue = current_pc;
maybe_one_more = 1;
continue; /* jmp , jl */
}
}
}
if (current_pc >= scan_limit)
{
if (pl_endptr)
{
if (after_stack_adjust != 0)
/* We did not find a "mv fp,sp", but we DID find
a stack_adjust. Is it safe to use that as the
end of the prologue? I just don't know. */
{
*pl_endptr = after_stack_adjust;
}
else
/* We reached the end of the loop without finding the end
of the prologue. No way to win -- we should report failure.
The way we do that is to return the original start_pc.
GDB will set a breakpoint at the start of the function (etc.) */
*pl_endptr = start_pc;
}
return;
}
if (after_prologue == 0)
after_prologue = current_pc;
if (pl_endptr)
*pl_endptr = after_prologue;
} /* decode_prologue */
/* Function: skip_prologue
Find end of function prologue */
#define DEFAULT_SEARCH_LIMIT 44
CORE_ADDR
m32r_skip_prologue (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)
{
func_end = 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. */
{
func_end = min (func_end, func_addr + DEFAULT_SEARCH_LIMIT);
}
}
else
func_end = pc + DEFAULT_SEARCH_LIMIT;
decode_prologue (pc, func_end, &sal.end);
return sal.end;
}
struct m32r_unwind_cache
{
/* The previous frame's inner most stack address. Used as this
frame ID's stack_addr. */
CORE_ADDR prev_sp;
/* The frame's base, optionally used by the high-level debug info. */
CORE_ADDR base;
int size;
/* How far the SP and r13 (FP) have been offset from the start of
the stack frame (as defined by the previous frame's stack
pointer). */
LONGEST sp_offset;
LONGEST r13_offset;
int uses_frame;
/* Table indicating the location of each and every register. */
struct trad_frame_saved_reg *saved_regs;
};
/* Put here the code to store, into fi->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. */
static struct m32r_unwind_cache *
m32r_frame_unwind_cache (struct frame_info *next_frame,
void **this_prologue_cache)
{
CORE_ADDR pc;
ULONGEST prev_sp;
ULONGEST this_base;
unsigned long op;
int i;
struct m32r_unwind_cache *info;
if ((*this_prologue_cache))
return (*this_prologue_cache);
info = FRAME_OBSTACK_ZALLOC (struct m32r_unwind_cache);
(*this_prologue_cache) = info;
info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
info->size = 0;
info->sp_offset = 0;
info->uses_frame = 0;
for (pc = frame_func_unwind (next_frame);
pc > 0 && pc < frame_pc_unwind (next_frame); pc += 2)
{
if ((pc & 2) == 0)
{
op = get_frame_memory_unsigned (next_frame, pc, 4);
if ((op & 0x80000000) == 0x80000000)
{
/* 32-bit instruction */
if ((op & 0xffff0000) == 0x8faf0000)
{
/* add3 sp,sp,xxxx */
short n = op & 0xffff;
info->sp_offset += n;
}
else if (((op >> 8) == 0xe4) && /* ld24 r4, xxxxxx; sub sp, r4 */
get_frame_memory_unsigned (next_frame, pc + 4,
2) == 0x0f24)
{
unsigned long n = op & 0xffffff;
info->sp_offset += n;
pc += 2;
}
else
break;
pc += 2;
continue;
}
}
/* 16-bit instructions */
op = get_frame_memory_unsigned (next_frame, pc, 2) & 0x7fff;
if ((op & 0xf0ff) == 0x207f)
{
/* st rn, @-sp */
int regno = ((op >> 8) & 0xf);
info->sp_offset -= 4;
info->saved_regs[regno].addr = info->sp_offset;
}
else if ((op & 0xff00) == 0x4f00)
{
/* addi sp, xx */
int n = (char) (op & 0xff);
info->sp_offset += n;
}
else if (op == 0x1d8f)
{
/* mv fp, sp */
info->uses_frame = 1;
info->r13_offset = info->sp_offset;
}
else if (op == 0x7000)
/* nop */
continue;
else
break;
}
info->size = -info->sp_offset;
/* Compute the previous frame's stack pointer (which is also the
frame's ID's stack address), and this frame's base pointer. */
if (info->uses_frame)
{
/* The SP was moved to the FP. This indicates that a new frame
was created. Get THIS frame's FP value by unwinding it from
the next frame. */
frame_unwind_unsigned_register (next_frame, M32R_FP_REGNUM, &this_base);
/* The FP points at the last saved register. Adjust the FP back
to before the first saved register giving the SP. */
prev_sp = this_base + info->size;
}
else
{
/* Assume that the FP is this frame's SP but with that pushed
stack space added back. */
frame_unwind_unsigned_register (next_frame, M32R_SP_REGNUM, &this_base);
prev_sp = this_base + info->size;
}
/* Convert that SP/BASE into real addresses. */
info->prev_sp = prev_sp;
info->base = this_base;
/* Adjust all the saved registers so that they contain addresses and
not offsets. */
for (i = 0; i < NUM_REGS - 1; i++)
if (trad_frame_addr_p (info->saved_regs, i))
info->saved_regs[i].addr = (info->prev_sp + info->saved_regs[i].addr);
/* The call instruction moves the caller's PC in the callee's LR.
Since this is an unwind, do the reverse. Copy the location of LR
into PC (the address / regnum) so that a request for PC will be
converted into a request for the LR. */
info->saved_regs[M32R_PC_REGNUM] = info->saved_regs[LR_REGNUM];
/* The previous frame's SP needed to be computed. Save the computed
value. */
trad_frame_set_value (info->saved_regs, M32R_SP_REGNUM, prev_sp);
return info;
}
static CORE_ADDR
m32r_read_pc (ptid_t ptid)
{
ptid_t save_ptid;
CORE_ADDR pc;
save_ptid = inferior_ptid;
inferior_ptid = ptid;
pc = (int) read_register (M32R_PC_REGNUM);
inferior_ptid = save_ptid;
return pc;
}
static void
m32r_write_pc (CORE_ADDR val, ptid_t ptid)
{
ptid_t save_ptid;
save_ptid = inferior_ptid;
inferior_ptid = ptid;
write_register (M32R_PC_REGNUM, val);
inferior_ptid = save_ptid;
}
static CORE_ADDR
m32r_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
ULONGEST sp;
frame_unwind_unsigned_register (next_frame, M32R_SP_REGNUM, &sp);
return sp;
}
static CORE_ADDR
m32r_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
struct value **args, CORE_ADDR sp, int struct_return,
CORE_ADDR struct_addr)
{
int stack_offset, stack_alloc;
int argreg = ARG1_REGNUM;
int argnum;
struct type *type;
enum type_code typecode;
CORE_ADDR regval;
char *val;
char valbuf[MAX_REGISTER_SIZE];
int len;
int odd_sized_struct;
/* first force sp to a 4-byte alignment */
sp = sp & ~3;
/* Set the return address. For the m32r, the return breakpoint is
always at BP_ADDR. */
regcache_cooked_write_unsigned (regcache, LR_REGNUM, bp_addr);
/* If STRUCT_RETURN is true, then the struct return address (in
STRUCT_ADDR) will consume the first argument-passing register.
Both adjust the register count and store that value. */
if (struct_return)
{
regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
argreg++;
}
/* 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 */
for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
{
type = VALUE_TYPE (args[argnum]);
typecode = TYPE_CODE (type);
len = TYPE_LENGTH (type);
memset (valbuf, 0, sizeof (valbuf));
/* Passes structures that do not fit in 2 registers by reference. */
if (len > 8
&& (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION))
{
store_unsigned_integer (valbuf, 4, VALUE_ADDRESS (args[argnum]));
typecode = TYPE_CODE_PTR;
len = 4;
val = valbuf;
}
else if (len < 4)
{
/* value gets right-justified in the register or stack word */
memcpy (valbuf + (REGISTER_RAW_SIZE (argreg) - len),
(char *) VALUE_CONTENTS (args[argnum]), len);
val = valbuf;
}
else
val = (char *) VALUE_CONTENTS (args[argnum]);
while (len > 0)
{
if (argreg > ARGN_REGNUM)
{
/* must go on the stack */
write_memory (sp + stack_offset, val, 4);
stack_offset += 4;
}
else if (argreg <= ARGN_REGNUM)
{
/* there's room in a register */
regval =
extract_unsigned_integer (val, REGISTER_RAW_SIZE (argreg));
regcache_cooked_write_unsigned (regcache, argreg++, regval);
}
/* 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);
}
}
/* Finally, update the SP register. */
regcache_cooked_write_unsigned (regcache, M32R_SP_REGNUM, sp);
return sp;
}
/* Given a return value in `regbuf' with a type `valtype',
extract and copy its value into `valbuf'. */
static void
m32r_extract_return_value (struct type *type, struct regcache *regcache,
void *dst)
{
bfd_byte *valbuf = dst;
int len = TYPE_LENGTH (type);
ULONGEST tmp;
/* By using store_unsigned_integer we avoid having to do
anything special for small big-endian values. */
regcache_cooked_read_unsigned (regcache, RET1_REGNUM, &tmp);
store_unsigned_integer (valbuf, (len > 4 ? len - 4 : len), tmp);
/* Ignore return values more than 8 bytes in size because the m32r
returns anything more than 8 bytes in the stack. */
if (len > 4)
{
regcache_cooked_read_unsigned (regcache, RET1_REGNUM + 1, &tmp);
store_unsigned_integer (valbuf + len - 4, 4, tmp);
}
}
static CORE_ADDR
m32r_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
ULONGEST pc;
frame_unwind_unsigned_register (next_frame, M32R_PC_REGNUM, &pc);
return pc;
}
/* Given a GDB frame, determine the address of the calling function's
frame. This will be used to create a new GDB frame struct. */
static void
m32r_frame_this_id (struct frame_info *next_frame,
void **this_prologue_cache, struct frame_id *this_id)
{
struct m32r_unwind_cache *info
= m32r_frame_unwind_cache (next_frame, this_prologue_cache);
CORE_ADDR base;
CORE_ADDR func;
struct minimal_symbol *msym_stack;
struct frame_id id;
/* The FUNC is easy. */
func = frame_func_unwind (next_frame);
/* This is meant to halt the backtrace at "_start". Make sure we
don't halt it at a generic dummy frame. */
if (inside_entry_file (func))
return;
/* Check if the stack is empty. */
msym_stack = lookup_minimal_symbol ("_stack", NULL, NULL);
if (msym_stack && info->base == SYMBOL_VALUE_ADDRESS (msym_stack))
return;
/* Hopefully the prologue analysis either correctly determined the
frame's base (which is the SP from the previous frame), or set
that base to "NULL". */
base = info->prev_sp;
if (base == 0)
return;
id = frame_id_build (base, func);
/* Check that we're not going round in circles with the same frame
ID (but avoid applying the test to sentinel frames which do go
round in circles). Can't use frame_id_eq() as that doesn't yet
compare the frame's PC value. */
if (frame_relative_level (next_frame) >= 0
&& get_frame_type (next_frame) != DUMMY_FRAME
&& frame_id_eq (get_frame_id (next_frame), id))
return;
(*this_id) = id;
}
static void
m32r_frame_prev_register (struct frame_info *next_frame,
void **this_prologue_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, void *bufferp)
{
struct m32r_unwind_cache *info
= m32r_frame_unwind_cache (next_frame, this_prologue_cache);
trad_frame_prev_register (next_frame, info->saved_regs, regnum,
optimizedp, lvalp, addrp, realnump, bufferp);
}
static const struct frame_unwind m32r_frame_unwind = {
NORMAL_FRAME,
m32r_frame_this_id,
m32r_frame_prev_register
};
static const struct frame_unwind *
m32r_frame_p (CORE_ADDR pc)
{
return &m32r_frame_unwind;
}
static CORE_ADDR
m32r_frame_base_address (struct frame_info *next_frame, void **this_cache)
{
struct m32r_unwind_cache *info
= m32r_frame_unwind_cache (next_frame, this_cache);
return info->base;
}
static const struct frame_base m32r_frame_base = {
&m32r_frame_unwind,
m32r_frame_base_address,
m32r_frame_base_address,
m32r_frame_base_address
};
/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
dummy frame. The frame ID's base needs to match the TOS value
saved by save_dummy_frame_tos(), and the PC match the dummy frame's
breakpoint. */
static struct frame_id
m32r_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
return frame_id_build (m32r_unwind_sp (gdbarch, next_frame),
frame_pc_unwind (next_frame));
}
static gdbarch_init_ftype m32r_gdbarch_init;
static struct gdbarch *
m32r_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch *gdbarch;
struct gdbarch_tdep *tdep;
/* If there is already a candidate, use it. */
arches = gdbarch_list_lookup_by_info (arches, &info);
if (arches != NULL)
return arches->gdbarch;
/* Allocate space for the new architecture. */
tdep = XMALLOC (struct gdbarch_tdep);
gdbarch = gdbarch_alloc (&info, tdep);
set_gdbarch_read_pc (gdbarch, m32r_read_pc);
set_gdbarch_write_pc (gdbarch, m32r_write_pc);
set_gdbarch_unwind_sp (gdbarch, m32r_unwind_sp);
set_gdbarch_num_regs (gdbarch, m32r_num_regs ());
set_gdbarch_sp_regnum (gdbarch, M32R_SP_REGNUM);
set_gdbarch_register_name (gdbarch, m32r_register_name);
set_gdbarch_register_type (gdbarch, m32r_register_type);
set_gdbarch_extract_return_value (gdbarch, m32r_extract_return_value);
set_gdbarch_push_dummy_call (gdbarch, m32r_push_dummy_call);
set_gdbarch_store_return_value (gdbarch, m32r_store_return_value);
set_gdbarch_extract_struct_value_address (gdbarch,
m32r_extract_struct_value_address);
set_gdbarch_use_struct_convention (gdbarch, m32r_use_struct_convention);
set_gdbarch_skip_prologue (gdbarch, m32r_skip_prologue);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_decr_pc_after_break (gdbarch, 0);
set_gdbarch_function_start_offset (gdbarch, 0);
set_gdbarch_breakpoint_from_pc (gdbarch, m32r_breakpoint_from_pc);
set_gdbarch_memory_insert_breakpoint (gdbarch,
m32r_memory_insert_breakpoint);
set_gdbarch_memory_remove_breakpoint (gdbarch,
m32r_memory_remove_breakpoint);
set_gdbarch_frame_args_skip (gdbarch, 0);
set_gdbarch_frameless_function_invocation (gdbarch,
frameless_look_for_prologue);
set_gdbarch_frame_align (gdbarch, m32r_frame_align);
frame_unwind_append_predicate (gdbarch, m32r_frame_p);
frame_base_set_default (gdbarch, &m32r_frame_base);
/* Methods for saving / extracting a dummy frame's ID. The ID's
stack address must match the SP value returned by
PUSH_DUMMY_CALL, and saved by generic_save_dummy_frame_tos. */
set_gdbarch_unwind_dummy_id (gdbarch, m32r_unwind_dummy_id);
/* Return the unwound PC value. */
set_gdbarch_unwind_pc (gdbarch, m32r_unwind_pc);
set_gdbarch_print_insn (gdbarch, print_insn_m32r);
return gdbarch;
}
void
_initialize_m32r_tdep (void)
{
register_gdbarch_init (bfd_arch_m32r, m32r_gdbarch_init);
}
[-- Attachment #4: m32r-rom.c --]
[-- Type: application/octet-stream, Size: 22341 bytes --]
/* Remote debugging interface to m32r and mon2000 ROM monitors for GDB,
the GNU debugger.
Copyright 1996, 1997, 1998, 1999, 2000, 2001
Free Software Foundation, Inc.
Adapted by Michael Snyder of Cygnus Support.
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. */
/* This module defines communication with the Renesas m32r monitor */
#include "defs.h"
#include "gdbcore.h"
#include "target.h"
#include "monitor.h"
#include "serial.h"
#include "symtab.h"
#include "command.h"
#include "gdbcmd.h"
#include "symfile.h" /* for generic load */
#include <time.h> /* for time_t */
#include "gdb_string.h"
#include "objfiles.h" /* for ALL_OBJFILES etc. */
#include "inferior.h" /* for write_pc() */
#include <ctype.h>
#include "regcache.h"
extern void report_transfer_performance (unsigned long, time_t, time_t);
/*
* All this stuff just to get my host computer's IP address!
*/
#include <sys/types.h>
#include <netdb.h> /* for hostent */
#include <netinet/in.h> /* for struct in_addr */
#if 1
#include <arpa/inet.h> /* for inet_ntoa */
#endif
static char *board_addr; /* user-settable IP address for M32R-EVA */
static char *server_addr; /* user-settable IP address for gdb host */
static char *download_path; /* user-settable path for SREC files */
/* REGNUM */
#define PSW_REGNUM 16
#define SPI_REGNUM 18
#define SPU_REGNUM 19
#define ACCL_REGNUM 22
#define ACCH_REGNUM 23
/*
* Function: m32r_load_1 (helper function)
*/
static void
m32r_load_section (bfd *abfd, asection *s, void *obj)
{
unsigned int *data_count = obj;
if (s->flags & SEC_LOAD)
{
bfd_size_type section_size = bfd_section_size (abfd, s);
bfd_vma section_base = bfd_section_lma (abfd, s);
unsigned int buffer, i;
*data_count += section_size;
printf_filtered ("Loading section %s, size 0x%lx lma ",
bfd_section_name (abfd, s), section_size);
print_address_numeric (section_base, 1, gdb_stdout);
printf_filtered ("\n");
gdb_flush (gdb_stdout);
monitor_printf ("%s mw\r", paddr_nz (section_base));
for (i = 0; i < section_size; i += 4)
{
QUIT;
monitor_expect (" -> ", NULL, 0);
bfd_get_section_contents (abfd, s, (char *) &buffer, i, 4);
monitor_printf ("%x\n", buffer);
}
monitor_expect (" -> ", NULL, 0);
monitor_printf ("q\n");
monitor_expect_prompt (NULL, 0);
}
}
static int
m32r_load_1 (void *dummy)
{
int data_count = 0;
bfd_map_over_sections ((bfd *) dummy, m32r_load_section, &data_count);
return data_count;
}
/*
* Function: m32r_load (an alternate way to load)
*/
static void
m32r_load (char *filename, int from_tty)
{
bfd *abfd;
asection *s;
unsigned int i, data_count = 0;
time_t start_time, end_time; /* for timing of download */
if (filename == NULL || filename[0] == 0)
filename = get_exec_file (1);
abfd = bfd_openr (filename, 0);
if (!abfd)
error ("Unable to open file %s\n", filename);
if (bfd_check_format (abfd, bfd_object) == 0)
error ("File is not an object file\n");
start_time = time (NULL);
#if 0
for (s = abfd->sections; s; s = s->next)
if (s->flags & SEC_LOAD)
{
bfd_size_type section_size = bfd_section_size (abfd, s);
bfd_vma section_base = bfd_section_vma (abfd, s);
unsigned int buffer;
data_count += section_size;
printf_filtered ("Loading section %s, size 0x%lx vma ",
bfd_section_name (abfd, s), section_size);
print_address_numeric (section_base, 1, gdb_stdout);
printf_filtered ("\n");
gdb_flush (gdb_stdout);
monitor_printf ("%x mw\r", section_base);
for (i = 0; i < section_size; i += 4)
{
monitor_expect (" -> ", NULL, 0);
bfd_get_section_contents (abfd, s, (char *) &buffer, i, 4);
monitor_printf ("%x\n", buffer);
}
monitor_expect (" -> ", NULL, 0);
monitor_printf ("q\n");
monitor_expect_prompt (NULL, 0);
}
#else
if (!(catch_errors (m32r_load_1, abfd, "Load aborted!\n", RETURN_MASK_ALL)))
{
monitor_printf ("q\n");
return;
}
#endif
end_time = time (NULL);
printf_filtered ("Start address 0x%lx\n", bfd_get_start_address (abfd));
report_transfer_performance (data_count, start_time, end_time);
/* Finally, make the PC point at the start address */
if (exec_bfd)
write_pc (bfd_get_start_address (exec_bfd));
inferior_ptid = null_ptid; /* No process now */
/* This is necessary because many things were based on the PC at the
time that we attached to the monitor, which is no longer valid
now that we have loaded new code (and just changed the PC).
Another way to do this might be to call normal_stop, except that
the stack may not be valid, and things would get horribly
confused... */
clear_symtab_users ();
}
static void
m32r_load_gen (char *filename, int from_tty)
{
generic_load (filename, from_tty);
}
static void m32r_open (char *args, int from_tty);
static void mon2000_open (char *args, int from_tty);
/* This array of registers needs to match the indexes used by GDB. The
whole reason this exists is because the various ROM monitors use
different names than GDB does, and don't support all the registers
either. So, typing "info reg sp" becomes an "A7". */
static char *m32r_regnames[] =
{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"psw", "cbr", "spi", "spu", "bpc", "pc", "accl", "acch",
};
static void
m32r_supply_register (char *regname, int regnamelen, char *val, int vallen)
{
int regno;
int num_regs = sizeof (m32r_regnames) / sizeof (m32r_regnames[0]);
for (regno = 0; regno < num_regs; regno++)
if (strncmp (regname, m32r_regnames[regno], regnamelen) == 0)
break;
if (regno >= num_regs)
return; /* no match */
if (regno == ACCL_REGNUM)
{ /* special handling for 64-bit acc reg */
monitor_supply_register (ACCH_REGNUM, val);
val = strchr (val, ':'); /* skip past ':' to get 2nd word */
if (val != NULL)
monitor_supply_register (ACCL_REGNUM, val + 1);
}
else
{
monitor_supply_register (regno, val);
if (regno == PSW_REGNUM)
{
unsigned long psw = strtoul (val, NULL, 16);
char *zero = "00000000", *one = "00000001";
#ifdef SM_REGNUM
/* Stack mode bit */
monitor_supply_register (SM_REGNUM, (psw & 0x80) ? one : zero);
#endif
#ifdef BSM_REGNUM
/* Backup stack mode bit */
monitor_supply_register (BSM_REGNUM, (psw & 0x8000) ? one : zero);
#endif
#ifdef IE_REGNUM
/* Interrupt enable bit */
monitor_supply_register (IE_REGNUM, (psw & 0x40) ? one : zero);
#endif
#ifdef BIE_REGNUM
/* Backup interrupt enable bit */
monitor_supply_register (BIE_REGNUM, (psw & 0x4000) ? one : zero);
#endif
#ifdef COND_REGNUM
/* Condition bit (carry etc.) */
monitor_supply_register (COND_REGNUM, (psw & 0x1) ? one : zero);
#endif
#ifdef CBR_REGNUM
monitor_supply_register (CBR_REGNUM, (psw & 0x1) ? one : zero);
#endif
#ifdef BPC_REGNUM
monitor_supply_register (BPC_REGNUM, zero); /* KLUDGE: (???????) */
#endif
#ifdef BCARRY_REGNUM
monitor_supply_register (BCARRY_REGNUM, zero); /* KLUDGE: (??????) */
#endif
}
if (regno == SPI_REGNUM || regno == SPU_REGNUM)
{ /* special handling for stack pointer (spu or spi) */
unsigned long stackmode = read_register (PSW_REGNUM) & 0x80;
if (regno == SPI_REGNUM && !stackmode) /* SP == SPI */
monitor_supply_register (SP_REGNUM, val);
else if (regno == SPU_REGNUM && stackmode) /* SP == SPU */
monitor_supply_register (SP_REGNUM, val);
}
}
}
/* m32r RevC board monitor */
static struct target_ops m32r_ops;
static char *m32r_inits[] = { "\r", NULL };
static struct monitor_ops m32r_cmds;
static void
init_m32r_cmds (void)
{
m32r_cmds.flags = MO_CLR_BREAK_USES_ADDR | MO_REGISTER_VALUE_FIRST;
m32r_cmds.init = m32r_inits; /* Init strings */
m32r_cmds.cont = "go\r"; /* continue command */
m32r_cmds.step = "step\r"; /* single step */
m32r_cmds.stop = NULL; /* interrupt command */
m32r_cmds.set_break = "%x +bp\r"; /* set a breakpoint */
m32r_cmds.clr_break = "%x -bp\r"; /* clear a breakpoint */
m32r_cmds.clr_all_break = "bpoff\r"; /* clear all breakpoints */
m32r_cmds.fill = "%x %x %x fill\r"; /* fill (start length val) */
m32r_cmds.setmem.cmdb = "%x 1 %x fill\r"; /* setmem.cmdb (addr, value) */
m32r_cmds.setmem.cmdw = "%x 1 %x fillh\r"; /* setmem.cmdw (addr, value) */
m32r_cmds.setmem.cmdl = "%x 1 %x fillw\r"; /* setmem.cmdl (addr, value) */
m32r_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */
m32r_cmds.setmem.resp_delim = NULL; /* setmem.resp_delim */
m32r_cmds.setmem.term = NULL; /* setmem.term */
m32r_cmds.setmem.term_cmd = NULL; /* setmem.term_cmd */
m32r_cmds.getmem.cmdb = "%x %x dump\r"; /* getmem.cmdb (addr, len) */
m32r_cmds.getmem.cmdw = NULL; /* getmem.cmdw (addr, len) */
m32r_cmds.getmem.cmdl = NULL; /* getmem.cmdl (addr, len) */
m32r_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, len) */
m32r_cmds.getmem.resp_delim = ": "; /* getmem.resp_delim */
m32r_cmds.getmem.term = NULL; /* getmem.term */
m32r_cmds.getmem.term_cmd = NULL; /* getmem.term_cmd */
m32r_cmds.setreg.cmd = "%x to %%%s\r"; /* setreg.cmd (name, value) */
m32r_cmds.setreg.resp_delim = NULL; /* setreg.resp_delim */
m32r_cmds.setreg.term = NULL; /* setreg.term */
m32r_cmds.setreg.term_cmd = NULL; /* setreg.term_cmd */
m32r_cmds.getreg.cmd = NULL; /* getreg.cmd (name) */
m32r_cmds.getreg.resp_delim = NULL; /* getreg.resp_delim */
m32r_cmds.getreg.term = NULL; /* getreg.term */
m32r_cmds.getreg.term_cmd = NULL; /* getreg.term_cmd */
m32r_cmds.dump_registers = ".reg\r"; /* dump_registers */
m32r_cmds.register_pattern = "\\(\\w+\\) += \\([0-9a-fA-F]+\\b\\)"; /* register_pattern */
m32r_cmds.supply_register = m32r_supply_register; /* supply_register */
m32r_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */
m32r_cmds.load = NULL; /* download command */
m32r_cmds.loadresp = NULL; /* load response */
m32r_cmds.prompt = "ok "; /* monitor command prompt */
m32r_cmds.line_term = "\r"; /* end-of-line terminator */
m32r_cmds.cmd_end = NULL; /* optional command terminator */
m32r_cmds.target = &m32r_ops; /* target operations */
m32r_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */
m32r_cmds.regnames = m32r_regnames; /* registers names */
m32r_cmds.magic = MONITOR_OPS_MAGIC; /* magic */
} /* init_m32r_cmds */
static void
m32r_open (char *args, int from_tty)
{
monitor_open (args, &m32r_cmds, from_tty);
}
/* Mon2000 monitor (MSA2000 board) */
static struct target_ops mon2000_ops;
static struct monitor_ops mon2000_cmds;
static void
init_mon2000_cmds (void)
{
mon2000_cmds.flags = MO_CLR_BREAK_USES_ADDR | MO_REGISTER_VALUE_FIRST;
mon2000_cmds.init = m32r_inits; /* Init strings */
mon2000_cmds.cont = "go\r"; /* continue command */
mon2000_cmds.step = "step\r"; /* single step */
mon2000_cmds.stop = NULL; /* interrupt command */
mon2000_cmds.set_break = "%x +bp\r"; /* set a breakpoint */
mon2000_cmds.clr_break = "%x -bp\r"; /* clear a breakpoint */
mon2000_cmds.clr_all_break = "bpoff\r"; /* clear all breakpoints */
mon2000_cmds.fill = "%x %x %x fill\r"; /* fill (start length val) */
mon2000_cmds.setmem.cmdb = "%x 1 %x fill\r"; /* setmem.cmdb (addr, value) */
mon2000_cmds.setmem.cmdw = "%x 1 %x fillh\r"; /* setmem.cmdw (addr, value) */
mon2000_cmds.setmem.cmdl = "%x 1 %x fillw\r"; /* setmem.cmdl (addr, value) */
mon2000_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */
mon2000_cmds.setmem.resp_delim = NULL; /* setmem.resp_delim */
mon2000_cmds.setmem.term = NULL; /* setmem.term */
mon2000_cmds.setmem.term_cmd = NULL; /* setmem.term_cmd */
mon2000_cmds.getmem.cmdb = "%x %x dump\r"; /* getmem.cmdb (addr, len) */
mon2000_cmds.getmem.cmdw = NULL; /* getmem.cmdw (addr, len) */
mon2000_cmds.getmem.cmdl = NULL; /* getmem.cmdl (addr, len) */
mon2000_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, len) */
mon2000_cmds.getmem.resp_delim = ": "; /* getmem.resp_delim */
mon2000_cmds.getmem.term = NULL; /* getmem.term */
mon2000_cmds.getmem.term_cmd = NULL; /* getmem.term_cmd */
mon2000_cmds.setreg.cmd = "%x to %%%s\r"; /* setreg.cmd (name, value) */
mon2000_cmds.setreg.resp_delim = NULL; /* setreg.resp_delim */
mon2000_cmds.setreg.term = NULL; /* setreg.term */
mon2000_cmds.setreg.term_cmd = NULL; /* setreg.term_cmd */
mon2000_cmds.getreg.cmd = NULL; /* getreg.cmd (name) */
mon2000_cmds.getreg.resp_delim = NULL; /* getreg.resp_delim */
mon2000_cmds.getreg.term = NULL; /* getreg.term */
mon2000_cmds.getreg.term_cmd = NULL; /* getreg.term_cmd */
mon2000_cmds.dump_registers = ".reg\r"; /* dump_registers */
mon2000_cmds.register_pattern = "\\(\\w+\\) += \\([0-9a-fA-F]+\\b\\)"; /* register_pattern */
mon2000_cmds.supply_register = m32r_supply_register; /* supply_register */
mon2000_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */
mon2000_cmds.load = NULL; /* download command */
mon2000_cmds.loadresp = NULL; /* load response */
mon2000_cmds.prompt = "Mon2000>"; /* monitor command prompt */
mon2000_cmds.line_term = "\r"; /* end-of-line terminator */
mon2000_cmds.cmd_end = NULL; /* optional command terminator */
mon2000_cmds.target = &mon2000_ops; /* target operations */
mon2000_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */
mon2000_cmds.regnames = m32r_regnames; /* registers names */
mon2000_cmds.magic = MONITOR_OPS_MAGIC; /* magic */
} /* init_mon2000_cmds */
static void
mon2000_open (char *args, int from_tty)
{
monitor_open (args, &mon2000_cmds, from_tty);
}
/* Function: set_board_address
Tell the BootOne monitor what it's ethernet IP address is. */
static void
m32r_set_board_address (char *args, int from_tty)
{
int resp_len;
char buf[1024];
if (args && *args)
{
monitor_printf ("ulip %s\n", args);
resp_len = monitor_expect_prompt (buf, sizeof (buf));
/* now parse the result for success */
}
else
error ("Requires argument (IP address for M32R-EVA board)");
}
/* Function: set_server_address
Tell the BootOne monitor what gdb's ethernet IP address is. */
static void
m32r_set_server_address (char *args, int from_tty)
{
int resp_len;
char buf[1024];
if (args && *args)
{
monitor_printf ("uhip %s\n", args);
resp_len = monitor_expect_prompt (buf, sizeof (buf));
/* now parse the result for success */
}
else
error ("Requires argument (IP address of GDB's host computer)");
}
/* Function: set_download_path
Tell the BootOne monitor the default path for downloadable SREC files. */
static void
m32r_set_download_path (char *args, int from_tty)
{
int resp_len;
char buf[1024];
if (args && *args)
{
monitor_printf ("up %s\n", args);
resp_len = monitor_expect_prompt (buf, sizeof (buf));
/* now parse the result for success */
}
else
error ("Requires argument (default path for downloadable SREC files)");
}
static void
m32r_upload_command (char *args, int from_tty)
{
bfd *abfd;
asection *s;
time_t start_time, end_time; /* for timing of download */
int resp_len, data_count = 0;
char buf[1024];
struct hostent *hostent;
struct in_addr inet_addr;
/* first check to see if there's an ethernet port! */
monitor_printf ("ust\r");
resp_len = monitor_expect_prompt (buf, sizeof (buf));
if (!strchr (buf, ':'))
error ("No ethernet connection!");
if (board_addr == 0)
{
/* scan second colon in the output from the "ust" command */
char *myIPaddress = strchr (strchr (buf, ':') + 1, ':') + 1;
while (isspace (*myIPaddress))
myIPaddress++;
if (!strncmp (myIPaddress, "0.0.", 4)) /* empty */
error
("Please use 'set board-address' to set the M32R-EVA board's IP address.");
if (strchr (myIPaddress, '('))
*(strchr (myIPaddress, '(')) = '\0'; /* delete trailing junk */
board_addr = xstrdup (myIPaddress);
}
if (server_addr == 0)
{
buf[0] = 0;
gethostname (buf, sizeof (buf));
if (buf[0] != 0)
hostent = gethostbyname (buf);
if (hostent != 0)
{
#if 1
memcpy (&inet_addr.s_addr, hostent->h_addr,
sizeof (inet_addr.s_addr));
server_addr = (char *) inet_ntoa (inet_addr);
#else
server_addr = (char *) inet_ntoa (hostent->h_addr);
#endif
}
if (server_addr == 0) /* failed? */
error
("Need to know gdb host computer's IP address (use 'set server-address')");
}
if (args == 0 || args[0] == 0) /* no args: upload the current file */
args = get_exec_file (1);
if (args[0] != '/' && download_path == 0)
{
if (current_directory)
download_path = xstrdup (current_directory);
else
error
("Need to know default download path (use 'set download-path')");
}
start_time = time (NULL);
monitor_printf ("uhip %s\r", server_addr);
resp_len = monitor_expect_prompt (buf, sizeof (buf)); /* parse result? */
monitor_printf ("ulip %s\r", board_addr);
resp_len = monitor_expect_prompt (buf, sizeof (buf)); /* parse result? */
if (args[0] != '/')
monitor_printf ("up %s\r", download_path); /* use default path */
else
monitor_printf ("up\r"); /* rooted filename/path */
resp_len = monitor_expect_prompt (buf, sizeof (buf)); /* parse result? */
if (strrchr (args, '.') && !strcmp (strrchr (args, '.'), ".srec"))
monitor_printf ("ul %s\r", args);
else /* add ".srec" suffix */
monitor_printf ("ul %s.srec\r", args);
resp_len = monitor_expect_prompt (buf, sizeof (buf)); /* parse result? */
if (buf[0] == 0 || strstr (buf, "complete") == 0)
error
("Upload file not found: %s.srec\nCheck IP addresses and download path.",
args);
else
printf_filtered (" -- Ethernet load complete.\n");
end_time = time (NULL);
abfd = bfd_openr (args, 0);
if (abfd != NULL)
{ /* Download is done -- print section statistics */
if (bfd_check_format (abfd, bfd_object) == 0)
{
printf_filtered ("File is not an object file\n");
}
for (s = abfd->sections; s; s = s->next)
if (s->flags & SEC_LOAD)
{
bfd_size_type section_size = bfd_section_size (abfd, s);
bfd_vma section_base = bfd_section_lma (abfd, s);
unsigned int buffer;
data_count += section_size;
printf_filtered ("Loading section %s, size 0x%lx lma ",
bfd_section_name (abfd, s), section_size);
print_address_numeric (section_base, 1, gdb_stdout);
printf_filtered ("\n");
gdb_flush (gdb_stdout);
}
/* Finally, make the PC point at the start address */
write_pc (bfd_get_start_address (abfd));
report_transfer_performance (data_count, start_time, end_time);
printf_filtered ("Start address 0x%lx\n", bfd_get_start_address (abfd));
}
inferior_ptid = null_ptid; /* No process now */
/* This is necessary because many things were based on the PC at the
time that we attached to the monitor, which is no longer valid
now that we have loaded new code (and just changed the PC).
Another way to do this might be to call normal_stop, except that
the stack may not be valid, and things would get horribly
confused... */
clear_symtab_users ();
}
void
_initialize_m32r_rom (void)
{
/* Initialize m32r RevC monitor target */
init_m32r_cmds ();
init_monitor_ops (&m32r_ops);
m32r_ops.to_shortname = "m32r";
m32r_ops.to_longname = "m32r monitor";
m32r_ops.to_load = m32r_load_gen; /* monitor lacks a download command */
m32r_ops.to_doc = "Debug via the m32r monitor.\n\
Specify the serial device it is connected to (e.g. /dev/ttya).";
m32r_ops.to_open = m32r_open;
add_target (&m32r_ops);
/* Initialize mon2000 monitor target */
init_mon2000_cmds ();
init_monitor_ops (&mon2000_ops);
mon2000_ops.to_shortname = "mon2000";
mon2000_ops.to_longname = "Mon2000 monitor";
mon2000_ops.to_load = m32r_load_gen; /* monitor lacks a download command */
mon2000_ops.to_doc = "Debug via the Mon2000 monitor.\n\
Specify the serial device it is connected to (e.g. /dev/ttya).";
mon2000_ops.to_open = mon2000_open;
add_target (&mon2000_ops);
add_show_from_set
(add_set_cmd ("download-path", class_obscure, var_string,
(char *) &download_path,
"Set the default path for downloadable SREC files.",
&setlist), &showlist);
add_show_from_set
(add_set_cmd ("board-address", class_obscure, var_string,
(char *) &board_addr,
"Set IP address for M32R-EVA target board.",
&setlist), &showlist);
add_show_from_set
(add_set_cmd ("server-address", class_obscure, var_string,
(char *) &server_addr,
"Set IP address for download server (GDB's host computer).",
&setlist), &showlist);
add_com ("upload", class_obscure, m32r_upload_command,
"Upload the srec file via the monitor's Ethernet upload capability.");
add_com ("tload", class_obscure, m32r_load, "test upload command.");
}
[-- Attachment #5: m32r-stub.c --]
[-- Type: application/octet-stream, Size: 48658 bytes --]
/****************************************************************************
THIS SOFTWARE IS NOT COPYRIGHTED
HP offers the following for use in the public domain. HP makes no
warranty with regard to the software or it's performance and the
user accepts the software "AS IS" with all faults.
HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
****************************************************************************/
/****************************************************************************
* Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
*
* Module name: remcom.c $
* Revision: 1.34 $
* Date: 91/03/09 12:29:49 $
* Contributor: Lake Stevens Instrument Division$
*
* Description: low level support for gdb debugger. $
*
* Considerations: only works on target hardware $
*
* Written by: Glenn Engel $
* ModuleState: Experimental $
*
* NOTES: See Below $
*
* Modified for M32R by Michael Snyder, Cygnus Support.
*
* To enable debugger support, two things need to happen. One, a
* call to set_debug_traps() is necessary in order to allow any breakpoints
* or error conditions to be properly intercepted and reported to gdb.
* Two, a breakpoint needs to be generated to begin communication. This
* is most easily accomplished by a call to breakpoint(). Breakpoint()
* simulates a breakpoint by executing a trap #1.
*
* The external function exceptionHandler() is
* used to attach a specific handler to a specific M32R vector number.
* It should use the same privilege level it runs at. It should
* install it as an interrupt gate so that interrupts are masked
* while the handler runs.
*
* Because gdb will sometimes write to the stack area to execute function
* calls, this program cannot rely on using the supervisor stack so it
* uses it's own stack area reserved in the int array remcomStack.
*
*************
*
* The following gdb commands are supported:
*
* command function Return value
*
* g return the value of the CPU registers hex data or ENN
* G set the value of the CPU registers OK or ENN
*
* mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
* MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
* XAA..AA,LLLL: Write LLLL binary bytes at address OK or ENN
* AA..AA
*
* c Resume at current address SNN ( signal NN)
* cAA..AA Continue at address AA..AA SNN
*
* s Step one instruction SNN
* sAA..AA Step one instruction from AA..AA SNN
*
* k kill
*
* ? What was the last sigval ? SNN (signal NN)
*
* All commands and responses are sent with a packet which includes a
* checksum. A packet consists of
*
* $<packet info>#<checksum>.
*
* where
* <packet info> :: <characters representing the command or response>
* <checksum> :: <two hex digits computed as modulo 256 sum of <packetinfo>>
*
* When a packet is received, it is first acknowledged with either '+' or '-'.
* '+' indicates a successful transfer. '-' indicates a failed transfer.
*
* Example:
*
* Host: Reply:
* $m0,10#2a +$00010203040506070809101112131415#42
*
****************************************************************************/
/************************************************************************
*
* external low-level support routines
*/
extern void putDebugChar (); /* write a single character */
extern int getDebugChar (); /* read and return a single char */
extern void exceptionHandler (); /* assign an exception handler */
/*****************************************************************************
* BUFMAX defines the maximum number of characters in inbound/outbound buffers
* at least NUMREGBYTES*2 are needed for register packets
*/
#define BUFMAX 400
static char initialized; /* boolean flag. != 0 means we've been initialized */
int remote_debug;
/* debug > 0 prints ill-formed commands in valid packets & checksum errors */
static const unsigned char hexchars[] = "0123456789abcdef";
#define NUMREGS 24
/* Number of bytes of registers. */
#define NUMREGBYTES (NUMREGS * 4)
enum regnames
{ R0, R1, R2, R3, R4, R5, R6, R7,
R8, R9, R10, R11, R12, R13, R14, R15,
PSW, CBR, SPI, SPU, BPC, PC, ACCL, ACCH
};
enum SYS_calls
{
SYS_null,
SYS_exit,
SYS_open,
SYS_close,
SYS_read,
SYS_write,
SYS_lseek,
SYS_unlink,
SYS_getpid,
SYS_kill,
SYS_fstat,
SYS_sbrk,
SYS_fork,
SYS_execve,
SYS_wait4,
SYS_link,
SYS_chdir,
SYS_stat,
SYS_utime,
SYS_chown,
SYS_chmod,
SYS_time,
SYS_pipe
};
static int registers[NUMREGS];
#define STACKSIZE 8096
static unsigned char remcomInBuffer[BUFMAX];
static unsigned char remcomOutBuffer[BUFMAX];
static int remcomStack[STACKSIZE / sizeof (int)];
static int *stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1];
static unsigned int save_vectors[18]; /* previous exception vectors */
/* Indicate to caller of mem2hex or hex2mem that there has been an error. */
static volatile int mem_err = 0;
/* Store the vector number here (since GDB only gets the signal
number through the usual means, and that's not very specific). */
int gdb_m32r_vector = -1;
#if 0
#include "syscall.h" /* for SYS_exit, SYS_write etc. */
#endif
/* Global entry points:
*/
extern void handle_exception (int);
extern void set_debug_traps (void);
extern void breakpoint (void);
/* Local functions:
*/
static int computeSignal (int);
static void putpacket (unsigned char *);
static unsigned char *getpacket (void);
static unsigned char *mem2hex (unsigned char *, unsigned char *, int, int);
static unsigned char *hex2mem (unsigned char *, unsigned char *, int, int);
static int hexToInt (unsigned char **, int *);
static unsigned char *bin2mem (unsigned char *, unsigned char *, int, int);
static void stash_registers (void);
static void restore_registers (void);
static int prepare_to_step (int);
static int finish_from_step (void);
static unsigned long crc32 (unsigned char *, int, unsigned long);
static void gdb_error (char *, char *);
static int gdb_putchar (int), gdb_puts (char *), gdb_write (char *, int);
static unsigned char *strcpy (unsigned char *, const unsigned char *);
static int strlen (const unsigned char *);
/*
* This function does all command procesing for interfacing to gdb.
*/
void
handle_exception (int exceptionVector)
{
int sigval, stepping;
int addr, length, i;
unsigned char *ptr;
unsigned char buf[16];
int binary;
if (!finish_from_step ())
return; /* "false step": let the target continue */
gdb_m32r_vector = exceptionVector;
if (remote_debug)
{
mem2hex ((unsigned char *) &exceptionVector, buf, 4, 0);
gdb_error ("Handle exception %s, ", buf);
mem2hex ((unsigned char *) ®isters[PC], buf, 4, 0);
gdb_error ("PC == 0x%s\n", buf);
}
/* reply to host that an exception has occurred */
sigval = computeSignal (exceptionVector);
ptr = remcomOutBuffer;
*ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */
*ptr++ = hexchars[sigval >> 4];
*ptr++ = hexchars[sigval & 0xf];
*ptr++ = hexchars[PC >> 4];
*ptr++ = hexchars[PC & 0xf];
*ptr++ = ':';
ptr = mem2hex ((unsigned char *) ®isters[PC], ptr, 4, 0); /* PC */
*ptr++ = ';';
*ptr++ = hexchars[R13 >> 4];
*ptr++ = hexchars[R13 & 0xf];
*ptr++ = ':';
ptr = mem2hex ((unsigned char *) ®isters[R13], ptr, 4, 0); /* FP */
*ptr++ = ';';
*ptr++ = hexchars[R15 >> 4];
*ptr++ = hexchars[R15 & 0xf];
*ptr++ = ':';
ptr = mem2hex ((unsigned char *) ®isters[R15], ptr, 4, 0); /* SP */
*ptr++ = ';';
*ptr++ = 0;
if (exceptionVector == 0) /* simulated SYS call stuff */
{
mem2hex ((unsigned char *) ®isters[PC], buf, 4, 0);
switch (registers[R0])
{
case SYS_exit:
gdb_error ("Target program has exited at %s\n", buf);
ptr = remcomOutBuffer;
*ptr++ = 'W';
sigval = registers[R1] & 0xff;
*ptr++ = hexchars[sigval >> 4];
*ptr++ = hexchars[sigval & 0xf];
*ptr++ = 0;
break;
case SYS_open:
gdb_error ("Target attempts SYS_open call at %s\n", buf);
break;
case SYS_close:
gdb_error ("Target attempts SYS_close call at %s\n", buf);
break;
case SYS_read:
gdb_error ("Target attempts SYS_read call at %s\n", buf);
break;
case SYS_write:
if (registers[R1] == 1 || /* write to stdout */
registers[R1] == 2) /* write to stderr */
{ /* (we can do that) */
registers[R0] =
gdb_write ((void *) registers[R2], registers[R3]);
return;
}
else
gdb_error ("Target attempts SYS_write call at %s\n", buf);
break;
case SYS_lseek:
gdb_error ("Target attempts SYS_lseek call at %s\n", buf);
break;
case SYS_unlink:
gdb_error ("Target attempts SYS_unlink call at %s\n", buf);
break;
case SYS_getpid:
gdb_error ("Target attempts SYS_getpid call at %s\n", buf);
break;
case SYS_kill:
gdb_error ("Target attempts SYS_kill call at %s\n", buf);
break;
case SYS_fstat:
gdb_error ("Target attempts SYS_fstat call at %s\n", buf);
break;
default:
gdb_error ("Target attempts unknown SYS call at %s\n", buf);
break;
}
}
putpacket (remcomOutBuffer);
stepping = 0;
while (1 == 1)
{
remcomOutBuffer[0] = 0;
ptr = getpacket ();
binary = 0;
switch (*ptr++)
{
default: /* Unknown code. Return an empty reply message. */
break;
case 'R':
if (hexToInt (&ptr, &addr))
registers[PC] = addr;
strcpy (remcomOutBuffer, "OK");
break;
case '!':
strcpy (remcomOutBuffer, "OK");
break;
case 'X': /* XAA..AA,LLLL:<binary data>#cs */
binary = 1;
case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
/* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
{
if (hexToInt (&ptr, &addr))
if (*(ptr++) == ',')
if (hexToInt (&ptr, &length))
if (*(ptr++) == ':')
{
mem_err = 0;
if (binary)
bin2mem (ptr, (unsigned char *) addr, length, 1);
else
hex2mem (ptr, (unsigned char *) addr, length, 1);
if (mem_err)
{
strcpy (remcomOutBuffer, "E03");
gdb_error ("memory fault", "");
}
else
{
strcpy (remcomOutBuffer, "OK");
}
ptr = 0;
}
if (ptr)
{
strcpy (remcomOutBuffer, "E02");
}
}
break;
case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
/* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
if (hexToInt (&ptr, &addr))
if (*(ptr++) == ',')
if (hexToInt (&ptr, &length))
{
ptr = 0;
mem_err = 0;
mem2hex ((unsigned char *) addr, remcomOutBuffer, length,
1);
if (mem_err)
{
strcpy (remcomOutBuffer, "E03");
gdb_error ("memory fault", "");
}
}
if (ptr)
{
strcpy (remcomOutBuffer, "E01");
}
break;
case '?':
remcomOutBuffer[0] = 'S';
remcomOutBuffer[1] = hexchars[sigval >> 4];
remcomOutBuffer[2] = hexchars[sigval % 16];
remcomOutBuffer[3] = 0;
break;
case 'd':
remote_debug = !(remote_debug); /* toggle debug flag */
break;
case 'g': /* return the value of the CPU registers */
mem2hex ((unsigned char *) registers, remcomOutBuffer, NUMREGBYTES,
0);
break;
case 'P': /* set the value of a single CPU register - return OK */
{
int regno;
if (hexToInt (&ptr, ®no) && *ptr++ == '=')
if (regno >= 0 && regno < NUMREGS)
{
int stackmode;
hex2mem (ptr, (unsigned char *) ®isters[regno], 4, 0);
/*
* Since we just changed a single CPU register, let's
* make sure to keep the several stack pointers consistant.
*/
stackmode = registers[PSW] & 0x80;
if (regno == R15) /* stack pointer changed */
{ /* need to change SPI or SPU */
if (stackmode == 0)
registers[SPI] = registers[R15];
else
registers[SPU] = registers[R15];
}
else if (regno == SPU) /* "user" stack pointer changed */
{
if (stackmode != 0) /* stack in user mode: copy SP */
registers[R15] = registers[SPU];
}
else if (regno == SPI) /* "interrupt" stack pointer changed */
{
if (stackmode == 0) /* stack in interrupt mode: copy SP */
registers[R15] = registers[SPI];
}
else if (regno == PSW) /* stack mode may have changed! */
{ /* force SP to either SPU or SPI */
if (stackmode == 0) /* stack in user mode */
registers[R15] = registers[SPI];
else /* stack in interrupt mode */
registers[R15] = registers[SPU];
}
strcpy (remcomOutBuffer, "OK");
break;
}
strcpy (remcomOutBuffer, "E01");
break;
}
case 'G': /* set the value of the CPU registers - return OK */
hex2mem (ptr, (unsigned char *) registers, NUMREGBYTES, 0);
strcpy (remcomOutBuffer, "OK");
break;
case 's': /* sAA..AA Step one instruction from AA..AA(optional) */
stepping = 1;
case 'c': /* cAA..AA Continue from address AA..AA(optional) */
/* try to read optional parameter, pc unchanged if no parm */
if (hexToInt (&ptr, &addr))
registers[PC] = addr;
if (stepping) /* single-stepping */
{
if (!prepare_to_step (0)) /* set up for single-step */
{
/* prepare_to_step has already emulated the target insn:
Send SIGTRAP to gdb, don't resume the target at all. */
ptr = remcomOutBuffer;
*ptr++ = 'T'; /* Simulate stopping with SIGTRAP */
*ptr++ = '0';
*ptr++ = '5';
*ptr++ = hexchars[PC >> 4]; /* send PC */
*ptr++ = hexchars[PC & 0xf];
*ptr++ = ':';
ptr = mem2hex ((unsigned char *) ®isters[PC], ptr, 4, 0);
*ptr++ = ';';
*ptr++ = hexchars[R13 >> 4]; /* send FP */
*ptr++ = hexchars[R13 & 0xf];
*ptr++ = ':';
ptr =
mem2hex ((unsigned char *) ®isters[R13], ptr, 4, 0);
*ptr++ = ';';
*ptr++ = hexchars[R15 >> 4]; /* send SP */
*ptr++ = hexchars[R15 & 0xf];
*ptr++ = ':';
ptr =
mem2hex ((unsigned char *) ®isters[R15], ptr, 4, 0);
*ptr++ = ';';
*ptr++ = 0;
break;
}
}
else /* continuing, not single-stepping */
{
/* OK, about to do a "continue". First check to see if the
target pc is on an odd boundary (second instruction in the
word). If so, we must do a single-step first, because
ya can't jump or return back to an odd boundary! */
if ((registers[PC] & 2) != 0)
prepare_to_step (1);
}
return;
case 'D': /* Detach */
#if 0
/* I am interpreting this to mean, release the board from control
by the remote stub. To do this, I am restoring the original
(or at least previous) exception vectors.
*/
for (i = 0; i < 18; i++)
exceptionHandler (i, save_vectors[i]);
putpacket ("OK");
return; /* continue the inferior */
#else
strcpy (remcomOutBuffer, "OK");
break;
#endif
case 'q':
if (*ptr++ == 'C' &&
*ptr++ == 'R' && *ptr++ == 'C' && *ptr++ == ':')
{
unsigned long start, len, our_crc;
if (hexToInt (&ptr, (int *) &start) &&
*ptr++ == ',' && hexToInt (&ptr, (int *) &len))
{
remcomOutBuffer[0] = 'C';
our_crc = crc32 ((unsigned char *) start, len, 0xffffffff);
mem2hex ((char *) &our_crc,
&remcomOutBuffer[1], sizeof (long), 0);
} /* else do nothing */
} /* else do nothing */
break;
case 'k': /* kill the program */
continue;
} /* switch */
/* reply to the request */
putpacket (remcomOutBuffer);
}
}
/* qCRC support */
/* Table used by the crc32 function to calcuate the checksum. */
static unsigned long crc32_table[256] = { 0, 0 };
static unsigned long
crc32 (unsigned char *buf, int len, unsigned long crc)
{
if (!crc32_table[1])
{
/* Initialize the CRC table and the decoding table. */
int i, j;
unsigned long c;
for (i = 0; i < 256; i++)
{
for (c = i << 24, j = 8; j > 0; --j)
c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1);
crc32_table[i] = c;
}
}
while (len--)
{
crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255];
buf++;
}
return crc;
}
static int
hex (unsigned char ch)
{
if ((ch >= 'a') && (ch <= 'f'))
return (ch - 'a' + 10);
if ((ch >= '0') && (ch <= '9'))
return (ch - '0');
if ((ch >= 'A') && (ch <= 'F'))
return (ch - 'A' + 10);
return (-1);
}
/* scan for the sequence $<data>#<checksum> */
unsigned char *
getpacket (void)
{
unsigned char *buffer = &remcomInBuffer[0];
unsigned char checksum;
unsigned char xmitcsum;
int count;
char ch;
while (1)
{
/* wait around for the start character, ignore all other characters */
while ((ch = getDebugChar ()) != '$')
;
retry:
checksum = 0;
xmitcsum = -1;
count = 0;
/* now, read until a # or end of buffer is found */
while (count < BUFMAX)
{
ch = getDebugChar ();
if (ch == '$')
goto retry;
if (ch == '#')
break;
checksum = checksum + ch;
buffer[count] = ch;
count = count + 1;
}
buffer[count] = 0;
if (ch == '#')
{
ch = getDebugChar ();
xmitcsum = hex (ch) << 4;
ch = getDebugChar ();
xmitcsum += hex (ch);
if (checksum != xmitcsum)
{
if (remote_debug)
{
unsigned char buf[16];
mem2hex ((unsigned char *) &checksum, buf, 4, 0);
gdb_error ("Bad checksum: my count = %s, ", buf);
mem2hex ((unsigned char *) &xmitcsum, buf, 4, 0);
gdb_error ("sent count = %s\n", buf);
gdb_error (" -- Bad buffer: \"%s\"\n", buffer);
}
putDebugChar ('-'); /* failed checksum */
}
else
{
putDebugChar ('+'); /* successful transfer */
/* if a sequence char is present, reply the sequence ID */
if (buffer[2] == ':')
{
putDebugChar (buffer[0]);
putDebugChar (buffer[1]);
return &buffer[3];
}
return &buffer[0];
}
}
}
}
/* send the packet in buffer. */
static void
putpacket (unsigned char *buffer)
{
unsigned char checksum;
int count;
char ch;
/* $<packet info>#<checksum>. */
do
{
putDebugChar ('$');
checksum = 0;
count = 0;
while (ch = buffer[count])
{
putDebugChar (ch);
checksum += ch;
count += 1;
}
putDebugChar ('#');
putDebugChar (hexchars[checksum >> 4]);
putDebugChar (hexchars[checksum % 16]);
}
while (getDebugChar () != '+');
}
/* Address of a routine to RTE to if we get a memory fault. */
static void (*volatile mem_fault_routine) () = 0;
static void
set_mem_err (void)
{
mem_err = 1;
}
/* Check the address for safe access ranges. As currently defined,
this routine will reject the "expansion bus" address range(s).
To make those ranges useable, someone must implement code to detect
whether there's anything connected to the expansion bus. */
static int
mem_safe (unsigned char *addr)
{
#define BAD_RANGE_ONE_START ((unsigned char *) 0x600000)
#define BAD_RANGE_ONE_END ((unsigned char *) 0xa00000)
#define BAD_RANGE_TWO_START ((unsigned char *) 0xff680000)
#define BAD_RANGE_TWO_END ((unsigned char *) 0xff800000)
if (addr < BAD_RANGE_ONE_START)
return 1; /* safe */
if (addr < BAD_RANGE_ONE_END)
return 0; /* unsafe */
if (addr < BAD_RANGE_TWO_START)
return 1; /* safe */
if (addr < BAD_RANGE_TWO_END)
return 0; /* unsafe */
}
/* These are separate functions so that they are so short and sweet
that the compiler won't save any registers (if there is a fault
to mem_fault, they won't get restored, so there better not be any
saved). */
static int
get_char (unsigned char *addr)
{
#if 1
if (mem_fault_routine && !mem_safe (addr))
{
mem_fault_routine ();
return 0;
}
#endif
return *addr;
}
static void
set_char (unsigned char *addr, unsigned char val)
{
#if 1
if (mem_fault_routine && !mem_safe (addr))
{
mem_fault_routine ();
return;
}
#endif
*addr = val;
}
/* Convert the memory pointed to by mem into hex, placing result in buf.
Return a pointer to the last char put in buf (null).
If MAY_FAULT is non-zero, then we should set mem_err in response to
a fault; if zero treat a fault like any other fault in the stub. */
static unsigned char *
mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault)
{
int i;
unsigned char ch;
if (may_fault)
mem_fault_routine = set_mem_err;
for (i = 0; i < count; i++)
{
ch = get_char (mem++);
if (may_fault && mem_err)
return (buf);
*buf++ = hexchars[ch >> 4];
*buf++ = hexchars[ch % 16];
}
*buf = 0;
if (may_fault)
mem_fault_routine = 0;
return (buf);
}
/* Convert the hex array pointed to by buf into binary to be placed in mem.
Return a pointer to the character AFTER the last byte written. */
static unsigned char *
hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault)
{
int i;
unsigned char ch;
if (may_fault)
mem_fault_routine = set_mem_err;
for (i = 0; i < count; i++)
{
ch = hex (*buf++) << 4;
ch = ch + hex (*buf++);
set_char (mem++, ch);
if (may_fault && mem_err)
return (mem);
}
if (may_fault)
mem_fault_routine = 0;
return (mem);
}
/* Convert the binary stream in BUF to memory.
Gdb will escape $, #, and the escape char (0x7d).
COUNT is the total number of bytes to write into
memory. */
static unsigned char *
bin2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault)
{
int i;
unsigned char ch;
if (may_fault)
mem_fault_routine = set_mem_err;
for (i = 0; i < count; i++)
{
/* Check for any escaped characters. Be paranoid and
only unescape chars that should be escaped. */
if (*buf == 0x7d)
{
switch (*(buf + 1))
{
case 0x3: /* # */
case 0x4: /* $ */
case 0x5d: /* escape char */
buf++;
*buf |= 0x20;
break;
default:
/* nothing */
break;
}
}
set_char (mem++, *buf++);
if (may_fault && mem_err)
return mem;
}
if (may_fault)
mem_fault_routine = 0;
return mem;
}
/* this function takes the m32r exception vector and attempts to
translate this number into a unix compatible signal value */
static int
computeSignal (int exceptionVector)
{
int sigval;
switch (exceptionVector)
{
case 0:
sigval = 23;
break; /* I/O trap */
case 1:
sigval = 5;
break; /* breakpoint */
case 2:
sigval = 5;
break; /* breakpoint */
case 3:
sigval = 5;
break; /* breakpoint */
case 4:
sigval = 5;
break; /* breakpoint */
case 5:
sigval = 5;
break; /* breakpoint */
case 6:
sigval = 5;
break; /* breakpoint */
case 7:
sigval = 5;
break; /* breakpoint */
case 8:
sigval = 5;
break; /* breakpoint */
case 9:
sigval = 5;
break; /* breakpoint */
case 10:
sigval = 5;
break; /* breakpoint */
case 11:
sigval = 5;
break; /* breakpoint */
case 12:
sigval = 5;
break; /* breakpoint */
case 13:
sigval = 5;
break; /* breakpoint */
case 14:
sigval = 5;
break; /* breakpoint */
case 15:
sigval = 5;
break; /* breakpoint */
case 16:
sigval = 10;
break; /* BUS ERROR (alignment) */
case 17:
sigval = 2;
break; /* INTerrupt */
default:
sigval = 7;
break; /* "software generated" */
}
return (sigval);
}
/**********************************************/
/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
/* RETURN NUMBER OF CHARS PROCESSED */
/**********************************************/
static int
hexToInt (unsigned char **ptr, int *intValue)
{
int numChars = 0;
int hexValue;
*intValue = 0;
while (**ptr)
{
hexValue = hex (**ptr);
if (hexValue >= 0)
{
*intValue = (*intValue << 4) | hexValue;
numChars++;
}
else
break;
(*ptr)++;
}
return (numChars);
}
/*
Table of branch instructions:
10B6 RTE return from trap or exception
1FCr JMP jump
1ECr JL jump and link
7Fxx BRA branch
FFxxxxxx BRA branch (long)
B09rxxxx BNEZ branch not-equal-zero
Br1rxxxx BNE branch not-equal
7Dxx BNC branch not-condition
FDxxxxxx BNC branch not-condition (long)
B0Arxxxx BLTZ branch less-than-zero
B0Crxxxx BLEZ branch less-equal-zero
7Exx BL branch and link
FExxxxxx BL branch and link (long)
B0Drxxxx BGTZ branch greater-than-zero
B0Brxxxx BGEZ branch greater-equal-zero
B08rxxxx BEQZ branch equal-zero
Br0rxxxx BEQ branch equal
7Cxx BC branch condition
FCxxxxxx BC branch condition (long)
*/
static int
isShortBranch (unsigned char *instr)
{
unsigned char instr0 = instr[0] & 0x7F; /* mask off high bit */
if (instr0 == 0x10 && instr[1] == 0xB6) /* RTE */
return 1; /* return from trap or exception */
if (instr0 == 0x1E || instr0 == 0x1F) /* JL or JMP */
if ((instr[1] & 0xF0) == 0xC0)
return 2; /* jump thru a register */
if (instr0 == 0x7C || instr0 == 0x7D || /* BC, BNC, BL, BRA */
instr0 == 0x7E || instr0 == 0x7F)
return 3; /* eight bit PC offset */
return 0;
}
static int
isLongBranch (unsigned char *instr)
{
if (instr[0] == 0xFC || instr[0] == 0xFD || /* BRA, BNC, BL, BC */
instr[0] == 0xFE || instr[0] == 0xFF) /* 24 bit relative */
return 4;
if ((instr[0] & 0xF0) == 0xB0) /* 16 bit relative */
{
if ((instr[1] & 0xF0) == 0x00 || /* BNE, BEQ */
(instr[1] & 0xF0) == 0x10)
return 5;
if (instr[0] == 0xB0) /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ, BEQZ */
if ((instr[1] & 0xF0) == 0x80 || (instr[1] & 0xF0) == 0x90 ||
(instr[1] & 0xF0) == 0xA0 || (instr[1] & 0xF0) == 0xB0 ||
(instr[1] & 0xF0) == 0xC0 || (instr[1] & 0xF0) == 0xD0)
return 6;
}
return 0;
}
/* if address is NOT on a 4-byte boundary, or high-bit of instr is zero,
then it's a 2-byte instruction, else it's a 4-byte instruction. */
#define INSTRUCTION_SIZE(addr) \
((((int) addr & 2) || (((unsigned char *) addr)[0] & 0x80) == 0) ? 2 : 4)
static int
isBranch (unsigned char *instr)
{
if (INSTRUCTION_SIZE (instr) == 2)
return isShortBranch (instr);
else
return isLongBranch (instr);
}
static int
willBranch (unsigned char *instr, int branchCode)
{
switch (branchCode)
{
case 0:
return 0; /* not a branch */
case 1:
return 1; /* RTE */
case 2:
return 1; /* JL or JMP */
case 3: /* BC, BNC, BL, BRA (short) */
case 4: /* BC, BNC, BL, BRA (long) */
switch (instr[0] & 0x0F)
{
case 0xC: /* Branch if Condition Register */
return (registers[CBR] != 0);
case 0xD: /* Branch if NOT Condition Register */
return (registers[CBR] == 0);
case 0xE: /* Branch and Link */
case 0xF: /* Branch (unconditional) */
return 1;
default: /* oops? */
return 0;
}
case 5: /* BNE, BEQ */
switch (instr[1] & 0xF0)
{
case 0x00: /* Branch if r1 equal to r2 */
return (registers[instr[0] & 0x0F] == registers[instr[1] & 0x0F]);
case 0x10: /* Branch if r1 NOT equal to r2 */
return (registers[instr[0] & 0x0F] != registers[instr[1] & 0x0F]);
default: /* oops? */
return 0;
}
case 6: /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ ,BEQZ */
switch (instr[1] & 0xF0)
{
case 0x80: /* Branch if reg equal to zero */
return (registers[instr[1] & 0x0F] == 0);
case 0x90: /* Branch if reg NOT equal to zero */
return (registers[instr[1] & 0x0F] != 0);
case 0xA0: /* Branch if reg less than zero */
return (registers[instr[1] & 0x0F] < 0);
case 0xB0: /* Branch if reg greater or equal to zero */
return (registers[instr[1] & 0x0F] >= 0);
case 0xC0: /* Branch if reg less than or equal to zero */
return (registers[instr[1] & 0x0F] <= 0);
case 0xD0: /* Branch if reg greater than zero */
return (registers[instr[1] & 0x0F] > 0);
default: /* oops? */
return 0;
}
default: /* oops? */
return 0;
}
}
static int
branchDestination (unsigned char *instr, int branchCode)
{
switch (branchCode)
{
default:
case 0: /* not a branch */
return 0;
case 1: /* RTE */
return registers[BPC] & ~3; /* pop BPC into PC */
case 2: /* JL or JMP */
return registers[instr[1] & 0x0F] & ~3; /* jump thru a register */
case 3: /* BC, BNC, BL, BRA (short, 8-bit relative offset) */
return (((int) instr) & ~3) + ((char) instr[1] << 2);
case 4: /* BC, BNC, BL, BRA (long, 24-bit relative offset) */
return ((int) instr +
((((char) instr[1] << 16) | (instr[2] << 8) | (instr[3])) <<
2));
case 5: /* BNE, BEQ (16-bit relative offset) */
case 6: /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ ,BEQZ (ditto) */
return ((int) instr + ((((char) instr[2] << 8) | (instr[3])) << 2));
}
/* An explanatory note: in the last three return expressions, I have
cast the most-significant byte of the return offset to char.
What this accomplishes is sign extension. If the other
less-significant bytes were signed as well, they would get sign
extended too and, if negative, their leading bits would clobber
the bits of the more-significant bytes ahead of them. There are
other ways I could have done this, but sign extension from
odd-sized integers is always a pain. */
}
static void
branchSideEffects (unsigned char *instr, int branchCode)
{
switch (branchCode)
{
case 1: /* RTE */
return; /* I <THINK> this is already handled... */
case 2: /* JL (or JMP) */
case 3: /* BL (or BC, BNC, BRA) */
case 4:
if ((instr[0] & 0x0F) == 0x0E) /* branch/jump and link */
registers[R14] = (registers[PC] & ~3) + 4;
return;
default: /* any other branch has no side effects */
return;
}
}
static struct STEPPING_CONTEXT
{
int stepping; /* true when we've started a single-step */
unsigned long target_addr; /* the instr we're trying to execute */
unsigned long target_size; /* the size of the target instr */
unsigned long noop_addr; /* where we've inserted a no-op, if any */
unsigned long trap1_addr; /* the trap following the target instr */
unsigned long trap2_addr; /* the trap at a branch destination, if any */
unsigned short noop_save; /* instruction overwritten by our no-op */
unsigned short trap1_save; /* instruction overwritten by trap1 */
unsigned short trap2_save; /* instruction overwritten by trap2 */
unsigned short continue_p; /* true if NOT returning to gdb after step */
} stepping;
/* Function: prepare_to_step
Called from handle_exception to prepare the user program to single-step.
Places a trap instruction after the target instruction, with special
extra handling for branch instructions and for instructions in the
second half-word of a word.
Returns: True if we should actually execute the instruction;
False if we are going to emulate executing the instruction,
in which case we simply report to GDB that the instruction
has already been executed. */
#define TRAP1 0x10f1; /* trap #1 instruction */
#define NOOP 0x7000; /* noop instruction */
static unsigned short trap1 = TRAP1;
static unsigned short noop = NOOP;
static int
prepare_to_step (continue_p)
int continue_p; /* if this isn't REALLY a single-step (see below) */
{
unsigned long pc = registers[PC];
int branchCode = isBranch ((unsigned char *) pc);
unsigned char *p;
/* zero out the stepping context
(paranoia -- it should already be zeroed) */
for (p = (unsigned char *) &stepping;
p < ((unsigned char *) &stepping) + sizeof (stepping); p++)
*p = 0;
if (branchCode != 0) /* next instruction is a branch */
{
branchSideEffects ((unsigned char *) pc, branchCode);
if (willBranch ((unsigned char *) pc, branchCode))
registers[PC] = branchDestination ((unsigned char *) pc, branchCode);
else
registers[PC] = pc + INSTRUCTION_SIZE (pc);
return 0; /* branch "executed" -- just notify GDB */
}
else if (((int) pc & 2) != 0) /* "second-slot" instruction */
{
/* insert no-op before pc */
stepping.noop_addr = pc - 2;
stepping.noop_save = *(unsigned short *) stepping.noop_addr;
*(unsigned short *) stepping.noop_addr = noop;
/* insert trap after pc */
stepping.trap1_addr = pc + 2;
stepping.trap1_save = *(unsigned short *) stepping.trap1_addr;
*(unsigned short *) stepping.trap1_addr = trap1;
}
else /* "first-slot" instruction */
{
/* insert trap after pc */
stepping.trap1_addr = pc + INSTRUCTION_SIZE (pc);
stepping.trap1_save = *(unsigned short *) stepping.trap1_addr;
*(unsigned short *) stepping.trap1_addr = trap1;
}
/* "continue_p" means that we are actually doing a continue, and not
being requested to single-step by GDB. Sometimes we have to do
one single-step before continuing, because the PC is on a half-word
boundary. There's no way to simply resume at such an address. */
stepping.continue_p = continue_p;
stepping.stepping = 1; /* starting a single-step */
return 1;
}
/* Function: finish_from_step
Called from handle_exception to finish up when the user program
returns from a single-step. Replaces the instructions that had
been overwritten by traps or no-ops,
Returns: True if we should notify GDB that the target stopped.
False if we only single-stepped because we had to before we
could continue (ie. we were trying to continue at a
half-word boundary). In that case don't notify GDB:
just "continue continuing". */
static int
finish_from_step (void)
{
if (stepping.stepping) /* anything to do? */
{
int continue_p = stepping.continue_p;
unsigned char *p;
if (stepping.noop_addr) /* replace instr "under" our no-op */
*(unsigned short *) stepping.noop_addr = stepping.noop_save;
if (stepping.trap1_addr) /* replace instr "under" our trap */
*(unsigned short *) stepping.trap1_addr = stepping.trap1_save;
if (stepping.trap2_addr) /* ditto our other trap, if any */
*(unsigned short *) stepping.trap2_addr = stepping.trap2_save;
for (p = (unsigned char *) &stepping; /* zero out the stepping context */
p < ((unsigned char *) &stepping) + sizeof (stepping); p++)
*p = 0;
return !(continue_p);
}
else /* we didn't single-step, therefore this must be a legitimate stop */
return 1;
}
struct PSWreg
{ /* separate out the bit flags in the PSW register */
int pad1:16;
int bsm:1;
int bie:1;
int pad2:5;
int bc:1;
int sm:1;
int ie:1;
int pad3:5;
int c:1;
} *psw;
/* Upon entry the value for LR to save has been pushed.
We unpush that so that the value for the stack pointer saved is correct.
Upon entry, all other registers are assumed to have not been modified
since the interrupt/trap occured. */
asm ("
stash_registers:
push r0
push r1
seth r1, #shigh(registers)
add3 r1, r1, #low(registers)
pop r0 ; r1
st r0, @(4,r1)
pop r0 ; r0
st r0, @r1
addi r1, #4 ; only add 4 as subsequent saves are `pre inc'
st r2, @+r1
st r3, @+r1
st r4, @+r1
st r5, @+r1
st r6, @+r1
st r7, @+r1
st r8, @+r1
st r9, @+r1
st r10, @+r1
st r11, @+r1
st r12, @+r1
st r13, @+r1 ; fp
pop r0 ; lr (r14)
st r0, @+r1
st sp, @+r1 ; sp contains right value at this point
mvfc r0, cr0
st r0, @+r1 ; cr0 == PSW
mvfc r0, cr1
st r0, @+r1 ; cr1 == CBR
mvfc r0, cr2
st r0, @+r1 ; cr2 == SPI
mvfc r0, cr3
st r0, @+r1 ; cr3 == SPU
mvfc r0, cr6
st r0, @+r1 ; cr6 == BPC
st r0, @+r1 ; PC == BPC
mvfaclo r0
st r0, @+r1 ; ACCL
mvfachi r0
st r0, @+r1 ; ACCH
jmp lr");
/* C routine to clean up what stash_registers did.
It is called after calling stash_registers.
This is separate from stash_registers as we want to do this in C
but doing stash_registers in C isn't straightforward. */
static void
cleanup_stash (void)
{
psw = (struct PSWreg *) ®isters[PSW]; /* fields of PSW register */
psw->sm = psw->bsm; /* fix up pre-trap values of psw fields */
psw->ie = psw->bie;
psw->c = psw->bc;
registers[CBR] = psw->bc; /* fix up pre-trap "C" register */
#if 0 /* FIXME: Was in previous version. Necessary?
(Remember that we use the "rte" insn to return from the
trap/interrupt so the values of bsm, bie, bc are important. */
psw->bsm = psw->bie = psw->bc = 0; /* zero post-trap values */
#endif
/* FIXME: Copied from previous version. This can probably be deleted
since methinks stash_registers has already done this. */
registers[PC] = registers[BPC]; /* pre-trap PC */
/* FIXME: Copied from previous version. Necessary? */
if (psw->sm) /* copy R15 into (psw->sm ? SPU : SPI) */
registers[SPU] = registers[R15];
else
registers[SPI] = registers[R15];
}
asm ("
restore_and_return:
seth r0, #shigh(registers+8)
add3 r0, r0, #low(registers+8)
ld r2, @r0+ ; restore r2
ld r3, @r0+ ; restore r3
ld r4, @r0+ ; restore r4
ld r5, @r0+ ; restore r5
ld r6, @r0+ ; restore r6
ld r7, @r0+ ; restore r7
ld r8, @r0+ ; restore r8
ld r9, @r0+ ; restore r9
ld r10, @r0+ ; restore r10
ld r11, @r0+ ; restore r11
ld r12, @r0+ ; restore r12
ld r13, @r0+ ; restore r13
ld r14, @r0+ ; restore r14
ld r15, @r0+ ; restore r15
ld r1, @r0+ ; restore cr0 == PSW
mvtc r1, cr0
ld r1, @r0+ ; restore cr1 == CBR (no-op, because it's read only)
mvtc r1, cr1
ld r1, @r0+ ; restore cr2 == SPI
mvtc r1, cr2
ld r1, @r0+ ; restore cr3 == SPU
mvtc r1, cr3
addi r0, #4 ; skip BPC
ld r1, @r0+ ; restore cr6 (BPC) == PC
mvtc r1, cr6
ld r1, @r0+ ; restore ACCL
mvtaclo r1
ld r1, @r0+ ; restore ACCH
mvtachi r1
seth r0, #shigh(registers)
add3 r0, r0, #low(registers)
ld r1, @(4,r0) ; restore r1
ld r0, @r0 ; restore r0
rte");
/* General trap handler, called after the registers have been stashed.
NUM is the trap/exception number. */
static void
process_exception (int num)
{
cleanup_stash ();
asm volatile ("
seth r1, #shigh(stackPtr)
add3 r1, r1, #low(stackPtr)
ld r15, @r1 ; setup local stack (protect user stack)
mv r0, %0
bl handle_exception
bl restore_and_return"::"r" (num):"r0", "r1");
}
void _catchException0 ();
asm ("
_catchException0:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #0
bl process_exception");
void _catchException1 ();
asm ("
_catchException1:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
bl cleanup_stash
seth r1, #shigh(stackPtr)
add3 r1, r1, #low(stackPtr)
ld r15, @r1 ; setup local stack (protect user stack)
seth r1, #shigh(registers + 21*4) ; PC
add3 r1, r1, #low(registers + 21*4)
ld r0, @r1
addi r0, #-4 ; back up PC for breakpoint trap.
st r0, @r1 ; FIXME: what about bp in right slot?
ldi r0, #1
bl handle_exception
bl restore_and_return");
void _catchException2 ();
asm ("
_catchException2:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #2
bl process_exception");
void _catchException3 ();
asm ("
_catchException3:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #3
bl process_exception");
void _catchException4 ();
asm ("
_catchException4:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #4
bl process_exception");
void _catchException5 ();
asm ("
_catchException5:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #5
bl process_exception");
void _catchException6 ();
asm ("
_catchException6:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #6
bl process_exception");
void _catchException7 ();
asm ("
_catchException7:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #7
bl process_exception");
void _catchException8 ();
asm ("
_catchException8:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #8
bl process_exception");
void _catchException9 ();
asm ("
_catchException9:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #9
bl process_exception");
void _catchException10 ();
asm ("
_catchException10:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #10
bl process_exception");
void _catchException11 ();
asm ("
_catchException11:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #11
bl process_exception");
void _catchException12 ();
asm ("
_catchException12:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #12
bl process_exception");
void _catchException13 ();
asm ("
_catchException13:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #13
bl process_exception");
void _catchException14 ();
asm ("
_catchException14:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #14
bl process_exception");
void _catchException15 ();
asm ("
_catchException15:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #15
bl process_exception");
void _catchException16 ();
asm ("
_catchException16:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #16
bl process_exception");
void _catchException17 ();
asm ("
_catchException17:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #17
bl process_exception");
/* this function is used to set up exception handlers for tracing and
breakpoints */
void
set_debug_traps (void)
{
/* extern void remcomHandler(); */
int i;
for (i = 0; i < 18; i++) /* keep a copy of old vectors */
if (save_vectors[i] == 0) /* only copy them the first time */
save_vectors[i] = getExceptionHandler (i);
stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1];
exceptionHandler (0, _catchException0);
exceptionHandler (1, _catchException1);
exceptionHandler (2, _catchException2);
exceptionHandler (3, _catchException3);
exceptionHandler (4, _catchException4);
exceptionHandler (5, _catchException5);
exceptionHandler (6, _catchException6);
exceptionHandler (7, _catchException7);
exceptionHandler (8, _catchException8);
exceptionHandler (9, _catchException9);
exceptionHandler (10, _catchException10);
exceptionHandler (11, _catchException11);
exceptionHandler (12, _catchException12);
exceptionHandler (13, _catchException13);
exceptionHandler (14, _catchException14);
exceptionHandler (15, _catchException15);
exceptionHandler (16, _catchException16);
/* exceptionHandler (17, _catchException17); */
initialized = 1;
}
/* This function will generate a breakpoint exception. It is used at the
beginning of a program to sync up with a debugger and can be used
otherwise as a quick means to stop program execution and "break" into
the debugger. */
#define BREAKPOINT() asm volatile (" trap #2");
void
breakpoint (void)
{
if (initialized)
BREAKPOINT ();
}
/* STDOUT section:
Stuff pertaining to simulating stdout by sending chars to gdb to be echoed.
Functions: gdb_putchar(char ch)
gdb_puts(char *str)
gdb_write(char *str, int len)
gdb_error(char *format, char *parm)
*/
/* Function: gdb_putchar(int)
Make gdb write a char to stdout.
Returns: the char */
static int
gdb_putchar (int ch)
{
char buf[4];
buf[0] = 'O';
buf[1] = hexchars[ch >> 4];
buf[2] = hexchars[ch & 0x0F];
buf[3] = 0;
putpacket (buf);
return ch;
}
/* Function: gdb_write(char *, int)
Make gdb write n bytes to stdout (not assumed to be null-terminated).
Returns: number of bytes written */
static int
gdb_write (char *data, int len)
{
char *buf, *cpy;
int i;
buf = remcomOutBuffer;
buf[0] = 'O';
i = 0;
while (i < len)
{
for (cpy = buf + 1;
i < len && cpy < buf + sizeof (remcomOutBuffer) - 3; i++)
{
*cpy++ = hexchars[data[i] >> 4];
*cpy++ = hexchars[data[i] & 0x0F];
}
*cpy = 0;
putpacket (buf);
}
return len;
}
/* Function: gdb_puts(char *)
Make gdb write a null-terminated string to stdout.
Returns: the length of the string */
static int
gdb_puts (char *str)
{
return gdb_write (str, strlen (str));
}
/* Function: gdb_error(char *, char *)
Send an error message to gdb's stdout.
First string may have 1 (one) optional "%s" in it, which
will cause the optional second string to be inserted. */
static void
gdb_error (char *format, char *parm)
{
char buf[400], *cpy;
int len;
if (remote_debug)
{
if (format && *format)
len = strlen (format);
else
return; /* empty input */
if (parm && *parm)
len += strlen (parm);
for (cpy = buf; *format;)
{
if (format[0] == '%' && format[1] == 's') /* include second string */
{
format += 2; /* advance two chars instead of just one */
while (parm && *parm)
*cpy++ = *parm++;
}
else
*cpy++ = *format++;
}
*cpy = '\0';
gdb_puts (buf);
}
}
static unsigned char *
strcpy (unsigned char *dest, const unsigned char *src)
{
unsigned char *ret = dest;
if (dest && src)
{
while (*src)
*dest++ = *src++;
*dest = 0;
}
return ret;
}
static int
strlen (const unsigned char *src)
{
int ret;
for (ret = 0; *src; src++)
ret++;
return ret;
}
#if 0
void
exit (code)
int code;
{
_exit (code);
}
int
atexit (void *p)
{
return 0;
}
void
abort (void)
{
_exit (1);
}
#endif
[-- Attachment #6: diffs --]
[-- Type: application/octet-stream, Size: 1209 bytes --]
diff -Naur insight-20030703.orig/src/configure insight-20030703/src/configure
--- insight-20030703.orig/src/configure Sat Jun 28 02:34:33 2003
+++ insight-20030703/src/configure Fri Jul 4 09:17:15 2003
@@ -1259,9 +1259,6 @@
i[3456789]86-*-beos*)
noconfigdirs="$noconfigdirs gdb target-newlib target-libgloss ${libgcj}"
;;
- m32r-*-*)
- noconfigdirs="$noconfigdirs ${libgcj} gdb"
- ;;
m68hc11-*-*|m6811-*-*|m68hc12-*-*|m6812-*-*)
noconfigdirs="$noconfigdirs target-libiberty target-libstdc++-v3 ${libgcj}"
;;
diff -Naur insight-20030703.orig/src/gdb/configure.tgt insight-20030703/src/gdb/configure.tgt
--- insight-20030703.orig/src/gdb/configure.tgt Sat Jun 14 02:49:49 2003
+++ insight-20030703/src/gdb/configure.tgt Fri Jul 4 09:17:15 2003
@@ -113,7 +113,7 @@
;;
ia64*-*-*) gdb_target=ia64 ;;
-# OBSOLETE m32r-*-elf*) gdb_target=m32r ;;
+m32r-*-*) gdb_target=m32r ;;
m68hc11*-*-*|m6811*-*-*) gdb_target=m68hc11 ;;
@@ -264,6 +264,7 @@
case "${gdb_target}" in
d10v) gdb_multi_arch=yes ;;
+m32r) gdb_multi_arch=yes ;;
m68hc11) gdb_multi_arch=yes ;;
mn10300) gdb_multi_arch=yes ;;
x86-64linux) gdb_multi_arch=yes ;;
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH] revised m32r target
2003-07-04 2:00 [PATCH] revised m32r target Kei Sakamoto
@ 2003-07-11 7:15 ` Kei Sakamoto
2003-07-11 13:31 ` Andrew Cagney
2003-07-21 18:49 ` Andrew Cagney
0 siblings, 2 replies; 8+ messages in thread
From: Kei Sakamoto @ 2003-07-11 7:15 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1317 bytes --]
Hello,
Would anyone take a look at this patch?
Is this OK to commit?
===
Kei Sakamoto
----- Original Message -----
From: "Kei Sakamoto" <sakamoto.kei@renesas.com>
To: <gdb-patches@sources.redhat.com>
Sent: Friday, July 04, 2003 11:02 AM
Subject: [PATCH] revised m32r target
> Hello,
>
> These are the revised m32r patches. The m32r is now pure
> multi-arched and contains no deprecated code.
>
> I attached the following new files:
> m32r-tdep.c
> m32r-stub.c
> m32r-rom.c
> config/m32r/m32r.mt
>
> I also attached a patch file for configure.tgt and toplevel
> configure.
>
> I tested the revised m32r target with sim and newlib.
>
> === gdb Summary ===
>
> # of expected passes 8008
> # of unexpected failures 39
> # of unexpected successes 3
> # of expected failures 52
> # of known failures 17
> # of unresolved testcases 1
> # of untested testcases 3
> # of unsupported tests 11
>
> While I was testing the revised m32r target, I found several
> bugs of gdb and testcases. I'll send patches for them later.
>
>
> 2003-07-04 Kei Sakamoto <sakamoto.kei@renesas.com>
>
> * configure.tgt : Add m32r-*-*.
> * m32r-rom.c, m32r-stub.c m32r-tdep.c,
> config/m32r/m32r.mt: New files.
>
[-- Attachment #2: m32r-tdep.c --]
[-- Type: application/octet-stream, Size: 28067 bytes --]
/* Target-dependent code for Renesas M32R, for GDB.
Copyright 1996, 1998, 1999, 2000, 2001, 2002, 2003 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 "frame.h"
#include "frame-unwind.h"
#include "frame-base.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "gdb_string.h"
#include "value.h"
#include "inferior.h"
#include "symfile.h"
#include "objfiles.h"
#include "language.h"
#include "arch-utils.h"
#include "regcache.h"
#include "trad-frame.h"
#include "gdb_assert.h"
struct gdbarch_tdep
{
/* gdbarch target dependent data here. Currently unused for M32R. */
};
/* m32r register names. */
enum
{
R0_REGNUM = 0,
R3_REGNUM = 3,
M32R_FP_REGNUM = 13,
LR_REGNUM = 14,
M32R_SP_REGNUM = 15,
PSW_REGNUM = 16,
M32R_PC_REGNUM = 21,
/* m32r calling convention. */
ARG1_REGNUM = R0_REGNUM,
ARGN_REGNUM = R3_REGNUM,
RET1_REGNUM = R0_REGNUM,
};
/* Local functions */
extern void _initialize_m32r_tdep (void);
static CORE_ADDR
m32r_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
{
/* Align to the size of an instruction (so that they can safely be
pushed onto the stack. */
return sp & ~3;
}
/* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of
EXTRACT_RETURN_VALUE? GCC_P is true if compiled with gcc
and TYPE is the type (which is known to be struct, union or array).
The m32r returns anything less than 8 bytes in size in
registers. */
static int
m32r_use_struct_convention (int gcc_p, struct type *type)
{
return (TYPE_LENGTH (type) > 8);
}
/* BREAKPOINT */
#define M32R_BE_BREAKPOINT32 {0x10, 0xf1, 0x70, 0x00}
#define M32R_LE_BREAKPOINT32 {0xf1, 0x10, 0x00, 0x70}
#define M32R_BE_BREAKPOINT16 {0x10, 0xf1}
#define M32R_LE_BREAKPOINT16 {0xf1, 0x10}
static int
m32r_memory_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
{
int val;
unsigned char *bp;
int bplen;
bplen = (addr & 3) ? 2 : 4;
/* Save the memory contents. */
val = target_read_memory (addr, contents_cache, bplen);
if (val != 0)
return val; /* return error */
/* Determine appropriate breakpoint contents and size for this address. */
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
if (((addr & 3) == 0) &&
((contents_cache[0] & 0x80) || (contents_cache[2] & 0x80)))
{
static unsigned char insn[] = M32R_BE_BREAKPOINT32;
bp = insn;
bplen = sizeof (insn);
}
else
{
static unsigned char insn[] = M32R_BE_BREAKPOINT16;
bp = insn;
bplen = sizeof (insn);
}
}
else
{ /* little-endian */
if (((addr & 3) == 0) &&
((contents_cache[1] & 0x80) || (contents_cache[3] & 0x80)))
{
static unsigned char insn[] = M32R_LE_BREAKPOINT32;
bp = insn;
bplen = sizeof (insn);
}
else
{
static unsigned char insn[] = M32R_LE_BREAKPOINT16;
bp = insn;
bplen = sizeof (insn);
}
}
/* Write the breakpoint. */
val = target_write_memory (addr, (char *) bp, bplen);
return val;
}
static int
m32r_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
{
int val;
int bplen;
/* Determine appropriate breakpoint contents and size for this address. */
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
if (((addr & 3) == 0) &&
((contents_cache[0] & 0x80) || (contents_cache[2] & 0x80)))
{
static unsigned char insn[] = M32R_BE_BREAKPOINT32;
bplen = sizeof (insn);
}
else
{
static unsigned char insn[] = M32R_BE_BREAKPOINT16;
bplen = sizeof (insn);
}
}
else
{
/* little-endian */
if (((addr & 3) == 0) &&
((contents_cache[1] & 0x80) || (contents_cache[3] & 0x80)))
{
static unsigned char insn[] = M32R_BE_BREAKPOINT32;
bplen = sizeof (insn);
}
else
{
static unsigned char insn[] = M32R_BE_BREAKPOINT16;
bplen = sizeof (insn);
}
}
/* Write contents. */
val = target_write_memory (addr, contents_cache, bplen);
return val;
}
static const unsigned char *
m32r_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
{
unsigned char *bp;
/* Determine appropriate breakpoint. */
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
if ((*pcptr & 3) == 0)
{
static unsigned char insn[] = M32R_BE_BREAKPOINT32;
bp = insn;
*lenptr = sizeof (insn);
}
else
{
static unsigned char insn[] = M32R_BE_BREAKPOINT16;
bp = insn;
*lenptr = sizeof (insn);
}
}
else
{
if ((*pcptr & 3) == 0)
{
static unsigned char insn[] = M32R_LE_BREAKPOINT32;
bp = insn;
*lenptr = sizeof (insn);
}
else
{
static unsigned char insn[] = M32R_LE_BREAKPOINT16;
bp = insn;
*lenptr = sizeof (insn);
}
}
return bp;
}
char *m32r_register_names[] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "fp", "lr", "sp",
"psw", "cbr", "spi", "spu", "bpc", "pc", "accl", "acch",
"evb"
};
static int
m32r_num_regs (void)
{
return (sizeof (m32r_register_names) / sizeof (m32r_register_names[0]));
}
static const char *
m32r_register_name (int reg_nr)
{
if (reg_nr < 0)
return NULL;
if (reg_nr >= m32r_num_regs ())
return NULL;
return m32r_register_names[reg_nr];
}
/* Return the GDB type object for the "standard" data type
of data in register N. */
static struct type *
m32r_register_type (struct gdbarch *gdbarch, int reg_nr)
{
if (reg_nr == M32R_PC_REGNUM)
return builtin_type_void_func_ptr;
else if (reg_nr == M32R_SP_REGNUM || reg_nr == M32R_FP_REGNUM)
return builtin_type_void_data_ptr;
else
return builtin_type_int32;
}
/* Write into appropriate registers a function return value
of type TYPE, given in virtual format.
Things always get returned in RET1_REGNUM, RET2_REGNUM. */
static void
m32r_store_return_value (struct type *type, struct regcache *regcache,
const void *valbuf)
{
CORE_ADDR regval;
int len = TYPE_LENGTH (type);
regval = extract_unsigned_integer (valbuf, len > 4 ? 4 : len);
regcache_cooked_write_unsigned (regcache, RET1_REGNUM, regval);
if (len > 4)
{
regval = extract_unsigned_integer (valbuf + 4, len - 4);
regcache_cooked_write_unsigned (regcache, RET1_REGNUM + 1, regval);
}
}
/* Extract from an array REGBUF containing the (raw) register state
the address in which a function should return its structure value,
as a CORE_ADDR (or an expression that can be used as one). */
static CORE_ADDR
m32r_extract_struct_value_address (struct regcache *regcache)
{
ULONGEST addr;
regcache_cooked_read_unsigned (regcache, ARG1_REGNUM, &addr);
return addr;
}
/* This is required by skip_prologue. The results of decoding a prologue
should be cached because this thrashing is getting nuts. */
static void
decode_prologue (CORE_ADDR start_pc, CORE_ADDR scan_limit,
CORE_ADDR *pl_endptr)
{
unsigned long framesize;
int insn;
int op1;
int maybe_one_more = 0;
CORE_ADDR after_prologue = 0;
CORE_ADDR after_stack_adjust = 0;
CORE_ADDR current_pc;
framesize = 0;
after_prologue = 0;
for (current_pc = start_pc; current_pc < scan_limit; current_pc += 2)
{
insn = read_memory_unsigned_integer (current_pc, 2);
/* If this is a 32 bit instruction, we dont want to examine its
immediate data as though it were an instruction */
if (current_pc & 0x02)
{
/* Clear the parallel execution bit from 16 bit instruction */
if (maybe_one_more)
{
/* The last instruction was a branch, usually terminates
the series, but if this is a parallel instruction,
it may be a stack framing instruction */
if (!(insn & 0x8000))
{
/* nope, we are really done */
break;
}
}
/* decode this instruction further */
insn &= 0x7fff;
}
else
{
if (maybe_one_more)
break; /* This isnt the one more */
if (insn & 0x8000)
{
if (current_pc == scan_limit)
scan_limit += 2; /* extend the search */
current_pc += 2; /* skip the immediate data */
if (insn == 0x8faf) /* add3 sp, sp, xxxx */
/* add 16 bit sign-extended offset */
{
framesize +=
-((short) read_memory_unsigned_integer (current_pc, 2));
}
else
{
if (((insn >> 8) == 0xe4) && /* ld24 r4, xxxxxx; sub sp, r4 */
read_memory_unsigned_integer (current_pc + 2,
2) == 0x0f24)
/* subtract 24 bit sign-extended negative-offset */
{
insn = read_memory_unsigned_integer (current_pc - 2, 4);
if (insn & 0x00800000) /* sign extend */
insn |= 0xff000000; /* negative */
else
insn &= 0x00ffffff; /* positive */
framesize += insn;
}
}
after_prologue = current_pc;
continue;
}
}
op1 = insn & 0xf000; /* isolate just the first nibble */
if ((insn & 0xf0ff) == 0x207f)
{ /* st reg, @-sp */
int regno;
framesize += 4;
regno = ((insn >> 8) & 0xf);
after_prologue = 0;
continue;
}
if ((insn >> 8) == 0x4f) /* addi sp, xx */
/* add 8 bit sign-extended offset */
{
int stack_adjust = (char) (insn & 0xff);
/* there are probably two of these stack adjustments:
1) A negative one in the prologue, and
2) A positive one in the epilogue.
We are only interested in the first one. */
if (stack_adjust < 0)
{
framesize -= stack_adjust;
after_prologue = 0;
/* A frameless function may have no "mv fp, sp".
In that case, this is the end of the prologue. */
after_stack_adjust = current_pc + 2;
}
continue;
}
if (insn == 0x1d8f)
{ /* mv fp, sp */
after_prologue = current_pc + 2;
break; /* end of stack adjustments */
}
/* Nop looks like a branch, continue explicitly */
if (insn == 0x7000)
{
after_prologue = current_pc + 2;
continue; /* nop occurs between pushes */
}
/* End of prolog if any of these are branch instructions */
if ((op1 == 0x7000) || (op1 == 0xb000) || (op1 == 0xf000))
{
after_prologue = current_pc;
maybe_one_more = 1;
continue;
}
/* Some of the branch instructions are mixed with other types */
if (op1 == 0x1000)
{
int subop = insn & 0x0ff0;
if ((subop == 0x0ec0) || (subop == 0x0fc0))
{
after_prologue = current_pc;
maybe_one_more = 1;
continue; /* jmp , jl */
}
}
}
if (current_pc >= scan_limit)
{
if (pl_endptr)
{
if (after_stack_adjust != 0)
/* We did not find a "mv fp,sp", but we DID find
a stack_adjust. Is it safe to use that as the
end of the prologue? I just don't know. */
{
*pl_endptr = after_stack_adjust;
}
else
/* We reached the end of the loop without finding the end
of the prologue. No way to win -- we should report failure.
The way we do that is to return the original start_pc.
GDB will set a breakpoint at the start of the function (etc.) */
*pl_endptr = start_pc;
}
return;
}
if (after_prologue == 0)
after_prologue = current_pc;
if (pl_endptr)
*pl_endptr = after_prologue;
} /* decode_prologue */
/* Function: skip_prologue
Find end of function prologue */
#define DEFAULT_SEARCH_LIMIT 44
CORE_ADDR
m32r_skip_prologue (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)
{
func_end = 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. */
{
func_end = min (func_end, func_addr + DEFAULT_SEARCH_LIMIT);
}
}
else
func_end = pc + DEFAULT_SEARCH_LIMIT;
decode_prologue (pc, func_end, &sal.end);
return sal.end;
}
struct m32r_unwind_cache
{
/* The previous frame's inner most stack address. Used as this
frame ID's stack_addr. */
CORE_ADDR prev_sp;
/* The frame's base, optionally used by the high-level debug info. */
CORE_ADDR base;
int size;
/* How far the SP and r13 (FP) have been offset from the start of
the stack frame (as defined by the previous frame's stack
pointer). */
LONGEST sp_offset;
LONGEST r13_offset;
int uses_frame;
/* Table indicating the location of each and every register. */
struct trad_frame_saved_reg *saved_regs;
};
/* Put here the code to store, into fi->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. */
static struct m32r_unwind_cache *
m32r_frame_unwind_cache (struct frame_info *next_frame,
void **this_prologue_cache)
{
CORE_ADDR pc;
ULONGEST prev_sp;
ULONGEST this_base;
unsigned long op;
int i;
struct m32r_unwind_cache *info;
if ((*this_prologue_cache))
return (*this_prologue_cache);
info = FRAME_OBSTACK_ZALLOC (struct m32r_unwind_cache);
(*this_prologue_cache) = info;
info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
info->size = 0;
info->sp_offset = 0;
info->uses_frame = 0;
for (pc = frame_func_unwind (next_frame);
pc > 0 && pc < frame_pc_unwind (next_frame); pc += 2)
{
if ((pc & 2) == 0)
{
op = get_frame_memory_unsigned (next_frame, pc, 4);
if ((op & 0x80000000) == 0x80000000)
{
/* 32-bit instruction */
if ((op & 0xffff0000) == 0x8faf0000)
{
/* add3 sp,sp,xxxx */
short n = op & 0xffff;
info->sp_offset += n;
}
else if (((op >> 8) == 0xe4) && /* ld24 r4, xxxxxx; sub sp, r4 */
get_frame_memory_unsigned (next_frame, pc + 4,
2) == 0x0f24)
{
unsigned long n = op & 0xffffff;
info->sp_offset += n;
pc += 2;
}
else
break;
pc += 2;
continue;
}
}
/* 16-bit instructions */
op = get_frame_memory_unsigned (next_frame, pc, 2) & 0x7fff;
if ((op & 0xf0ff) == 0x207f)
{
/* st rn, @-sp */
int regno = ((op >> 8) & 0xf);
info->sp_offset -= 4;
info->saved_regs[regno].addr = info->sp_offset;
}
else if ((op & 0xff00) == 0x4f00)
{
/* addi sp, xx */
int n = (char) (op & 0xff);
info->sp_offset += n;
}
else if (op == 0x1d8f)
{
/* mv fp, sp */
info->uses_frame = 1;
info->r13_offset = info->sp_offset;
}
else if (op == 0x7000)
/* nop */
continue;
else
break;
}
info->size = -info->sp_offset;
/* Compute the previous frame's stack pointer (which is also the
frame's ID's stack address), and this frame's base pointer. */
if (info->uses_frame)
{
/* The SP was moved to the FP. This indicates that a new frame
was created. Get THIS frame's FP value by unwinding it from
the next frame. */
frame_unwind_unsigned_register (next_frame, M32R_FP_REGNUM, &this_base);
/* The FP points at the last saved register. Adjust the FP back
to before the first saved register giving the SP. */
prev_sp = this_base + info->size;
}
else
{
/* Assume that the FP is this frame's SP but with that pushed
stack space added back. */
frame_unwind_unsigned_register (next_frame, M32R_SP_REGNUM, &this_base);
prev_sp = this_base + info->size;
}
/* Convert that SP/BASE into real addresses. */
info->prev_sp = prev_sp;
info->base = this_base;
/* Adjust all the saved registers so that they contain addresses and
not offsets. */
for (i = 0; i < NUM_REGS - 1; i++)
if (trad_frame_addr_p (info->saved_regs, i))
info->saved_regs[i].addr = (info->prev_sp + info->saved_regs[i].addr);
/* The call instruction moves the caller's PC in the callee's LR.
Since this is an unwind, do the reverse. Copy the location of LR
into PC (the address / regnum) so that a request for PC will be
converted into a request for the LR. */
info->saved_regs[M32R_PC_REGNUM] = info->saved_regs[LR_REGNUM];
/* The previous frame's SP needed to be computed. Save the computed
value. */
trad_frame_set_value (info->saved_regs, M32R_SP_REGNUM, prev_sp);
return info;
}
static CORE_ADDR
m32r_read_pc (ptid_t ptid)
{
ptid_t save_ptid;
CORE_ADDR pc;
save_ptid = inferior_ptid;
inferior_ptid = ptid;
pc = (int) read_register (M32R_PC_REGNUM);
inferior_ptid = save_ptid;
return pc;
}
static void
m32r_write_pc (CORE_ADDR val, ptid_t ptid)
{
ptid_t save_ptid;
save_ptid = inferior_ptid;
inferior_ptid = ptid;
write_register (M32R_PC_REGNUM, val);
inferior_ptid = save_ptid;
}
static CORE_ADDR
m32r_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
ULONGEST sp;
frame_unwind_unsigned_register (next_frame, M32R_SP_REGNUM, &sp);
return sp;
}
static CORE_ADDR
m32r_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
struct value **args, CORE_ADDR sp, int struct_return,
CORE_ADDR struct_addr)
{
int stack_offset, stack_alloc;
int argreg = ARG1_REGNUM;
int argnum;
struct type *type;
enum type_code typecode;
CORE_ADDR regval;
char *val;
char valbuf[MAX_REGISTER_SIZE];
int len;
int odd_sized_struct;
/* first force sp to a 4-byte alignment */
sp = sp & ~3;
/* Set the return address. For the m32r, the return breakpoint is
always at BP_ADDR. */
regcache_cooked_write_unsigned (regcache, LR_REGNUM, bp_addr);
/* If STRUCT_RETURN is true, then the struct return address (in
STRUCT_ADDR) will consume the first argument-passing register.
Both adjust the register count and store that value. */
if (struct_return)
{
regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
argreg++;
}
/* 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 */
for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
{
type = VALUE_TYPE (args[argnum]);
typecode = TYPE_CODE (type);
len = TYPE_LENGTH (type);
memset (valbuf, 0, sizeof (valbuf));
/* Passes structures that do not fit in 2 registers by reference. */
if (len > 8
&& (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION))
{
store_unsigned_integer (valbuf, 4, VALUE_ADDRESS (args[argnum]));
typecode = TYPE_CODE_PTR;
len = 4;
val = valbuf;
}
else if (len < 4)
{
/* value gets right-justified in the register or stack word */
memcpy (valbuf + (REGISTER_RAW_SIZE (argreg) - len),
(char *) VALUE_CONTENTS (args[argnum]), len);
val = valbuf;
}
else
val = (char *) VALUE_CONTENTS (args[argnum]);
while (len > 0)
{
if (argreg > ARGN_REGNUM)
{
/* must go on the stack */
write_memory (sp + stack_offset, val, 4);
stack_offset += 4;
}
else if (argreg <= ARGN_REGNUM)
{
/* there's room in a register */
regval =
extract_unsigned_integer (val, REGISTER_RAW_SIZE (argreg));
regcache_cooked_write_unsigned (regcache, argreg++, regval);
}
/* 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);
}
}
/* Finally, update the SP register. */
regcache_cooked_write_unsigned (regcache, M32R_SP_REGNUM, sp);
return sp;
}
/* Given a return value in `regbuf' with a type `valtype',
extract and copy its value into `valbuf'. */
static void
m32r_extract_return_value (struct type *type, struct regcache *regcache,
void *dst)
{
bfd_byte *valbuf = dst;
int len = TYPE_LENGTH (type);
ULONGEST tmp;
/* By using store_unsigned_integer we avoid having to do
anything special for small big-endian values. */
regcache_cooked_read_unsigned (regcache, RET1_REGNUM, &tmp);
store_unsigned_integer (valbuf, (len > 4 ? len - 4 : len), tmp);
/* Ignore return values more than 8 bytes in size because the m32r
returns anything more than 8 bytes in the stack. */
if (len > 4)
{
regcache_cooked_read_unsigned (regcache, RET1_REGNUM + 1, &tmp);
store_unsigned_integer (valbuf + len - 4, 4, tmp);
}
}
static CORE_ADDR
m32r_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
ULONGEST pc;
frame_unwind_unsigned_register (next_frame, M32R_PC_REGNUM, &pc);
return pc;
}
/* Given a GDB frame, determine the address of the calling function's
frame. This will be used to create a new GDB frame struct. */
static void
m32r_frame_this_id (struct frame_info *next_frame,
void **this_prologue_cache, struct frame_id *this_id)
{
struct m32r_unwind_cache *info
= m32r_frame_unwind_cache (next_frame, this_prologue_cache);
CORE_ADDR base;
CORE_ADDR func;
struct minimal_symbol *msym_stack;
struct frame_id id;
/* The FUNC is easy. */
func = frame_func_unwind (next_frame);
/* This is meant to halt the backtrace at "_start". Make sure we
don't halt it at a generic dummy frame. */
if (inside_entry_file (func))
return;
/* Check if the stack is empty. */
msym_stack = lookup_minimal_symbol ("_stack", NULL, NULL);
if (msym_stack && info->base == SYMBOL_VALUE_ADDRESS (msym_stack))
return;
/* Hopefully the prologue analysis either correctly determined the
frame's base (which is the SP from the previous frame), or set
that base to "NULL". */
base = info->prev_sp;
if (base == 0)
return;
id = frame_id_build (base, func);
/* Check that we're not going round in circles with the same frame
ID (but avoid applying the test to sentinel frames which do go
round in circles). Can't use frame_id_eq() as that doesn't yet
compare the frame's PC value. */
if (frame_relative_level (next_frame) >= 0
&& get_frame_type (next_frame) != DUMMY_FRAME
&& frame_id_eq (get_frame_id (next_frame), id))
return;
(*this_id) = id;
}
static void
m32r_frame_prev_register (struct frame_info *next_frame,
void **this_prologue_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, void *bufferp)
{
struct m32r_unwind_cache *info
= m32r_frame_unwind_cache (next_frame, this_prologue_cache);
trad_frame_prev_register (next_frame, info->saved_regs, regnum,
optimizedp, lvalp, addrp, realnump, bufferp);
}
static const struct frame_unwind m32r_frame_unwind = {
NORMAL_FRAME,
m32r_frame_this_id,
m32r_frame_prev_register
};
static const struct frame_unwind *
m32r_frame_p (CORE_ADDR pc)
{
return &m32r_frame_unwind;
}
static CORE_ADDR
m32r_frame_base_address (struct frame_info *next_frame, void **this_cache)
{
struct m32r_unwind_cache *info
= m32r_frame_unwind_cache (next_frame, this_cache);
return info->base;
}
static const struct frame_base m32r_frame_base = {
&m32r_frame_unwind,
m32r_frame_base_address,
m32r_frame_base_address,
m32r_frame_base_address
};
/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
dummy frame. The frame ID's base needs to match the TOS value
saved by save_dummy_frame_tos(), and the PC match the dummy frame's
breakpoint. */
static struct frame_id
m32r_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
return frame_id_build (m32r_unwind_sp (gdbarch, next_frame),
frame_pc_unwind (next_frame));
}
static gdbarch_init_ftype m32r_gdbarch_init;
static struct gdbarch *
m32r_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch *gdbarch;
struct gdbarch_tdep *tdep;
/* If there is already a candidate, use it. */
arches = gdbarch_list_lookup_by_info (arches, &info);
if (arches != NULL)
return arches->gdbarch;
/* Allocate space for the new architecture. */
tdep = XMALLOC (struct gdbarch_tdep);
gdbarch = gdbarch_alloc (&info, tdep);
set_gdbarch_read_pc (gdbarch, m32r_read_pc);
set_gdbarch_write_pc (gdbarch, m32r_write_pc);
set_gdbarch_unwind_sp (gdbarch, m32r_unwind_sp);
set_gdbarch_num_regs (gdbarch, m32r_num_regs ());
set_gdbarch_sp_regnum (gdbarch, M32R_SP_REGNUM);
set_gdbarch_register_name (gdbarch, m32r_register_name);
set_gdbarch_register_type (gdbarch, m32r_register_type);
set_gdbarch_extract_return_value (gdbarch, m32r_extract_return_value);
set_gdbarch_push_dummy_call (gdbarch, m32r_push_dummy_call);
set_gdbarch_store_return_value (gdbarch, m32r_store_return_value);
set_gdbarch_extract_struct_value_address (gdbarch,
m32r_extract_struct_value_address);
set_gdbarch_use_struct_convention (gdbarch, m32r_use_struct_convention);
set_gdbarch_skip_prologue (gdbarch, m32r_skip_prologue);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_decr_pc_after_break (gdbarch, 0);
set_gdbarch_function_start_offset (gdbarch, 0);
set_gdbarch_breakpoint_from_pc (gdbarch, m32r_breakpoint_from_pc);
set_gdbarch_memory_insert_breakpoint (gdbarch,
m32r_memory_insert_breakpoint);
set_gdbarch_memory_remove_breakpoint (gdbarch,
m32r_memory_remove_breakpoint);
set_gdbarch_frame_args_skip (gdbarch, 0);
set_gdbarch_frameless_function_invocation (gdbarch,
frameless_look_for_prologue);
set_gdbarch_frame_align (gdbarch, m32r_frame_align);
frame_unwind_append_predicate (gdbarch, m32r_frame_p);
frame_base_set_default (gdbarch, &m32r_frame_base);
/* Methods for saving / extracting a dummy frame's ID. The ID's
stack address must match the SP value returned by
PUSH_DUMMY_CALL, and saved by generic_save_dummy_frame_tos. */
set_gdbarch_unwind_dummy_id (gdbarch, m32r_unwind_dummy_id);
/* Return the unwound PC value. */
set_gdbarch_unwind_pc (gdbarch, m32r_unwind_pc);
set_gdbarch_print_insn (gdbarch, print_insn_m32r);
return gdbarch;
}
void
_initialize_m32r_tdep (void)
{
register_gdbarch_init (bfd_arch_m32r, m32r_gdbarch_init);
}
[-- Attachment #3: m32r-stub.c --]
[-- Type: application/octet-stream, Size: 48658 bytes --]
/****************************************************************************
THIS SOFTWARE IS NOT COPYRIGHTED
HP offers the following for use in the public domain. HP makes no
warranty with regard to the software or it's performance and the
user accepts the software "AS IS" with all faults.
HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
****************************************************************************/
/****************************************************************************
* Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
*
* Module name: remcom.c $
* Revision: 1.34 $
* Date: 91/03/09 12:29:49 $
* Contributor: Lake Stevens Instrument Division$
*
* Description: low level support for gdb debugger. $
*
* Considerations: only works on target hardware $
*
* Written by: Glenn Engel $
* ModuleState: Experimental $
*
* NOTES: See Below $
*
* Modified for M32R by Michael Snyder, Cygnus Support.
*
* To enable debugger support, two things need to happen. One, a
* call to set_debug_traps() is necessary in order to allow any breakpoints
* or error conditions to be properly intercepted and reported to gdb.
* Two, a breakpoint needs to be generated to begin communication. This
* is most easily accomplished by a call to breakpoint(). Breakpoint()
* simulates a breakpoint by executing a trap #1.
*
* The external function exceptionHandler() is
* used to attach a specific handler to a specific M32R vector number.
* It should use the same privilege level it runs at. It should
* install it as an interrupt gate so that interrupts are masked
* while the handler runs.
*
* Because gdb will sometimes write to the stack area to execute function
* calls, this program cannot rely on using the supervisor stack so it
* uses it's own stack area reserved in the int array remcomStack.
*
*************
*
* The following gdb commands are supported:
*
* command function Return value
*
* g return the value of the CPU registers hex data or ENN
* G set the value of the CPU registers OK or ENN
*
* mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
* MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
* XAA..AA,LLLL: Write LLLL binary bytes at address OK or ENN
* AA..AA
*
* c Resume at current address SNN ( signal NN)
* cAA..AA Continue at address AA..AA SNN
*
* s Step one instruction SNN
* sAA..AA Step one instruction from AA..AA SNN
*
* k kill
*
* ? What was the last sigval ? SNN (signal NN)
*
* All commands and responses are sent with a packet which includes a
* checksum. A packet consists of
*
* $<packet info>#<checksum>.
*
* where
* <packet info> :: <characters representing the command or response>
* <checksum> :: <two hex digits computed as modulo 256 sum of <packetinfo>>
*
* When a packet is received, it is first acknowledged with either '+' or '-'.
* '+' indicates a successful transfer. '-' indicates a failed transfer.
*
* Example:
*
* Host: Reply:
* $m0,10#2a +$00010203040506070809101112131415#42
*
****************************************************************************/
/************************************************************************
*
* external low-level support routines
*/
extern void putDebugChar (); /* write a single character */
extern int getDebugChar (); /* read and return a single char */
extern void exceptionHandler (); /* assign an exception handler */
/*****************************************************************************
* BUFMAX defines the maximum number of characters in inbound/outbound buffers
* at least NUMREGBYTES*2 are needed for register packets
*/
#define BUFMAX 400
static char initialized; /* boolean flag. != 0 means we've been initialized */
int remote_debug;
/* debug > 0 prints ill-formed commands in valid packets & checksum errors */
static const unsigned char hexchars[] = "0123456789abcdef";
#define NUMREGS 24
/* Number of bytes of registers. */
#define NUMREGBYTES (NUMREGS * 4)
enum regnames
{ R0, R1, R2, R3, R4, R5, R6, R7,
R8, R9, R10, R11, R12, R13, R14, R15,
PSW, CBR, SPI, SPU, BPC, PC, ACCL, ACCH
};
enum SYS_calls
{
SYS_null,
SYS_exit,
SYS_open,
SYS_close,
SYS_read,
SYS_write,
SYS_lseek,
SYS_unlink,
SYS_getpid,
SYS_kill,
SYS_fstat,
SYS_sbrk,
SYS_fork,
SYS_execve,
SYS_wait4,
SYS_link,
SYS_chdir,
SYS_stat,
SYS_utime,
SYS_chown,
SYS_chmod,
SYS_time,
SYS_pipe
};
static int registers[NUMREGS];
#define STACKSIZE 8096
static unsigned char remcomInBuffer[BUFMAX];
static unsigned char remcomOutBuffer[BUFMAX];
static int remcomStack[STACKSIZE / sizeof (int)];
static int *stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1];
static unsigned int save_vectors[18]; /* previous exception vectors */
/* Indicate to caller of mem2hex or hex2mem that there has been an error. */
static volatile int mem_err = 0;
/* Store the vector number here (since GDB only gets the signal
number through the usual means, and that's not very specific). */
int gdb_m32r_vector = -1;
#if 0
#include "syscall.h" /* for SYS_exit, SYS_write etc. */
#endif
/* Global entry points:
*/
extern void handle_exception (int);
extern void set_debug_traps (void);
extern void breakpoint (void);
/* Local functions:
*/
static int computeSignal (int);
static void putpacket (unsigned char *);
static unsigned char *getpacket (void);
static unsigned char *mem2hex (unsigned char *, unsigned char *, int, int);
static unsigned char *hex2mem (unsigned char *, unsigned char *, int, int);
static int hexToInt (unsigned char **, int *);
static unsigned char *bin2mem (unsigned char *, unsigned char *, int, int);
static void stash_registers (void);
static void restore_registers (void);
static int prepare_to_step (int);
static int finish_from_step (void);
static unsigned long crc32 (unsigned char *, int, unsigned long);
static void gdb_error (char *, char *);
static int gdb_putchar (int), gdb_puts (char *), gdb_write (char *, int);
static unsigned char *strcpy (unsigned char *, const unsigned char *);
static int strlen (const unsigned char *);
/*
* This function does all command procesing for interfacing to gdb.
*/
void
handle_exception (int exceptionVector)
{
int sigval, stepping;
int addr, length, i;
unsigned char *ptr;
unsigned char buf[16];
int binary;
if (!finish_from_step ())
return; /* "false step": let the target continue */
gdb_m32r_vector = exceptionVector;
if (remote_debug)
{
mem2hex ((unsigned char *) &exceptionVector, buf, 4, 0);
gdb_error ("Handle exception %s, ", buf);
mem2hex ((unsigned char *) ®isters[PC], buf, 4, 0);
gdb_error ("PC == 0x%s\n", buf);
}
/* reply to host that an exception has occurred */
sigval = computeSignal (exceptionVector);
ptr = remcomOutBuffer;
*ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */
*ptr++ = hexchars[sigval >> 4];
*ptr++ = hexchars[sigval & 0xf];
*ptr++ = hexchars[PC >> 4];
*ptr++ = hexchars[PC & 0xf];
*ptr++ = ':';
ptr = mem2hex ((unsigned char *) ®isters[PC], ptr, 4, 0); /* PC */
*ptr++ = ';';
*ptr++ = hexchars[R13 >> 4];
*ptr++ = hexchars[R13 & 0xf];
*ptr++ = ':';
ptr = mem2hex ((unsigned char *) ®isters[R13], ptr, 4, 0); /* FP */
*ptr++ = ';';
*ptr++ = hexchars[R15 >> 4];
*ptr++ = hexchars[R15 & 0xf];
*ptr++ = ':';
ptr = mem2hex ((unsigned char *) ®isters[R15], ptr, 4, 0); /* SP */
*ptr++ = ';';
*ptr++ = 0;
if (exceptionVector == 0) /* simulated SYS call stuff */
{
mem2hex ((unsigned char *) ®isters[PC], buf, 4, 0);
switch (registers[R0])
{
case SYS_exit:
gdb_error ("Target program has exited at %s\n", buf);
ptr = remcomOutBuffer;
*ptr++ = 'W';
sigval = registers[R1] & 0xff;
*ptr++ = hexchars[sigval >> 4];
*ptr++ = hexchars[sigval & 0xf];
*ptr++ = 0;
break;
case SYS_open:
gdb_error ("Target attempts SYS_open call at %s\n", buf);
break;
case SYS_close:
gdb_error ("Target attempts SYS_close call at %s\n", buf);
break;
case SYS_read:
gdb_error ("Target attempts SYS_read call at %s\n", buf);
break;
case SYS_write:
if (registers[R1] == 1 || /* write to stdout */
registers[R1] == 2) /* write to stderr */
{ /* (we can do that) */
registers[R0] =
gdb_write ((void *) registers[R2], registers[R3]);
return;
}
else
gdb_error ("Target attempts SYS_write call at %s\n", buf);
break;
case SYS_lseek:
gdb_error ("Target attempts SYS_lseek call at %s\n", buf);
break;
case SYS_unlink:
gdb_error ("Target attempts SYS_unlink call at %s\n", buf);
break;
case SYS_getpid:
gdb_error ("Target attempts SYS_getpid call at %s\n", buf);
break;
case SYS_kill:
gdb_error ("Target attempts SYS_kill call at %s\n", buf);
break;
case SYS_fstat:
gdb_error ("Target attempts SYS_fstat call at %s\n", buf);
break;
default:
gdb_error ("Target attempts unknown SYS call at %s\n", buf);
break;
}
}
putpacket (remcomOutBuffer);
stepping = 0;
while (1 == 1)
{
remcomOutBuffer[0] = 0;
ptr = getpacket ();
binary = 0;
switch (*ptr++)
{
default: /* Unknown code. Return an empty reply message. */
break;
case 'R':
if (hexToInt (&ptr, &addr))
registers[PC] = addr;
strcpy (remcomOutBuffer, "OK");
break;
case '!':
strcpy (remcomOutBuffer, "OK");
break;
case 'X': /* XAA..AA,LLLL:<binary data>#cs */
binary = 1;
case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
/* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
{
if (hexToInt (&ptr, &addr))
if (*(ptr++) == ',')
if (hexToInt (&ptr, &length))
if (*(ptr++) == ':')
{
mem_err = 0;
if (binary)
bin2mem (ptr, (unsigned char *) addr, length, 1);
else
hex2mem (ptr, (unsigned char *) addr, length, 1);
if (mem_err)
{
strcpy (remcomOutBuffer, "E03");
gdb_error ("memory fault", "");
}
else
{
strcpy (remcomOutBuffer, "OK");
}
ptr = 0;
}
if (ptr)
{
strcpy (remcomOutBuffer, "E02");
}
}
break;
case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
/* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
if (hexToInt (&ptr, &addr))
if (*(ptr++) == ',')
if (hexToInt (&ptr, &length))
{
ptr = 0;
mem_err = 0;
mem2hex ((unsigned char *) addr, remcomOutBuffer, length,
1);
if (mem_err)
{
strcpy (remcomOutBuffer, "E03");
gdb_error ("memory fault", "");
}
}
if (ptr)
{
strcpy (remcomOutBuffer, "E01");
}
break;
case '?':
remcomOutBuffer[0] = 'S';
remcomOutBuffer[1] = hexchars[sigval >> 4];
remcomOutBuffer[2] = hexchars[sigval % 16];
remcomOutBuffer[3] = 0;
break;
case 'd':
remote_debug = !(remote_debug); /* toggle debug flag */
break;
case 'g': /* return the value of the CPU registers */
mem2hex ((unsigned char *) registers, remcomOutBuffer, NUMREGBYTES,
0);
break;
case 'P': /* set the value of a single CPU register - return OK */
{
int regno;
if (hexToInt (&ptr, ®no) && *ptr++ == '=')
if (regno >= 0 && regno < NUMREGS)
{
int stackmode;
hex2mem (ptr, (unsigned char *) ®isters[regno], 4, 0);
/*
* Since we just changed a single CPU register, let's
* make sure to keep the several stack pointers consistant.
*/
stackmode = registers[PSW] & 0x80;
if (regno == R15) /* stack pointer changed */
{ /* need to change SPI or SPU */
if (stackmode == 0)
registers[SPI] = registers[R15];
else
registers[SPU] = registers[R15];
}
else if (regno == SPU) /* "user" stack pointer changed */
{
if (stackmode != 0) /* stack in user mode: copy SP */
registers[R15] = registers[SPU];
}
else if (regno == SPI) /* "interrupt" stack pointer changed */
{
if (stackmode == 0) /* stack in interrupt mode: copy SP */
registers[R15] = registers[SPI];
}
else if (regno == PSW) /* stack mode may have changed! */
{ /* force SP to either SPU or SPI */
if (stackmode == 0) /* stack in user mode */
registers[R15] = registers[SPI];
else /* stack in interrupt mode */
registers[R15] = registers[SPU];
}
strcpy (remcomOutBuffer, "OK");
break;
}
strcpy (remcomOutBuffer, "E01");
break;
}
case 'G': /* set the value of the CPU registers - return OK */
hex2mem (ptr, (unsigned char *) registers, NUMREGBYTES, 0);
strcpy (remcomOutBuffer, "OK");
break;
case 's': /* sAA..AA Step one instruction from AA..AA(optional) */
stepping = 1;
case 'c': /* cAA..AA Continue from address AA..AA(optional) */
/* try to read optional parameter, pc unchanged if no parm */
if (hexToInt (&ptr, &addr))
registers[PC] = addr;
if (stepping) /* single-stepping */
{
if (!prepare_to_step (0)) /* set up for single-step */
{
/* prepare_to_step has already emulated the target insn:
Send SIGTRAP to gdb, don't resume the target at all. */
ptr = remcomOutBuffer;
*ptr++ = 'T'; /* Simulate stopping with SIGTRAP */
*ptr++ = '0';
*ptr++ = '5';
*ptr++ = hexchars[PC >> 4]; /* send PC */
*ptr++ = hexchars[PC & 0xf];
*ptr++ = ':';
ptr = mem2hex ((unsigned char *) ®isters[PC], ptr, 4, 0);
*ptr++ = ';';
*ptr++ = hexchars[R13 >> 4]; /* send FP */
*ptr++ = hexchars[R13 & 0xf];
*ptr++ = ':';
ptr =
mem2hex ((unsigned char *) ®isters[R13], ptr, 4, 0);
*ptr++ = ';';
*ptr++ = hexchars[R15 >> 4]; /* send SP */
*ptr++ = hexchars[R15 & 0xf];
*ptr++ = ':';
ptr =
mem2hex ((unsigned char *) ®isters[R15], ptr, 4, 0);
*ptr++ = ';';
*ptr++ = 0;
break;
}
}
else /* continuing, not single-stepping */
{
/* OK, about to do a "continue". First check to see if the
target pc is on an odd boundary (second instruction in the
word). If so, we must do a single-step first, because
ya can't jump or return back to an odd boundary! */
if ((registers[PC] & 2) != 0)
prepare_to_step (1);
}
return;
case 'D': /* Detach */
#if 0
/* I am interpreting this to mean, release the board from control
by the remote stub. To do this, I am restoring the original
(or at least previous) exception vectors.
*/
for (i = 0; i < 18; i++)
exceptionHandler (i, save_vectors[i]);
putpacket ("OK");
return; /* continue the inferior */
#else
strcpy (remcomOutBuffer, "OK");
break;
#endif
case 'q':
if (*ptr++ == 'C' &&
*ptr++ == 'R' && *ptr++ == 'C' && *ptr++ == ':')
{
unsigned long start, len, our_crc;
if (hexToInt (&ptr, (int *) &start) &&
*ptr++ == ',' && hexToInt (&ptr, (int *) &len))
{
remcomOutBuffer[0] = 'C';
our_crc = crc32 ((unsigned char *) start, len, 0xffffffff);
mem2hex ((char *) &our_crc,
&remcomOutBuffer[1], sizeof (long), 0);
} /* else do nothing */
} /* else do nothing */
break;
case 'k': /* kill the program */
continue;
} /* switch */
/* reply to the request */
putpacket (remcomOutBuffer);
}
}
/* qCRC support */
/* Table used by the crc32 function to calcuate the checksum. */
static unsigned long crc32_table[256] = { 0, 0 };
static unsigned long
crc32 (unsigned char *buf, int len, unsigned long crc)
{
if (!crc32_table[1])
{
/* Initialize the CRC table and the decoding table. */
int i, j;
unsigned long c;
for (i = 0; i < 256; i++)
{
for (c = i << 24, j = 8; j > 0; --j)
c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1);
crc32_table[i] = c;
}
}
while (len--)
{
crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255];
buf++;
}
return crc;
}
static int
hex (unsigned char ch)
{
if ((ch >= 'a') && (ch <= 'f'))
return (ch - 'a' + 10);
if ((ch >= '0') && (ch <= '9'))
return (ch - '0');
if ((ch >= 'A') && (ch <= 'F'))
return (ch - 'A' + 10);
return (-1);
}
/* scan for the sequence $<data>#<checksum> */
unsigned char *
getpacket (void)
{
unsigned char *buffer = &remcomInBuffer[0];
unsigned char checksum;
unsigned char xmitcsum;
int count;
char ch;
while (1)
{
/* wait around for the start character, ignore all other characters */
while ((ch = getDebugChar ()) != '$')
;
retry:
checksum = 0;
xmitcsum = -1;
count = 0;
/* now, read until a # or end of buffer is found */
while (count < BUFMAX)
{
ch = getDebugChar ();
if (ch == '$')
goto retry;
if (ch == '#')
break;
checksum = checksum + ch;
buffer[count] = ch;
count = count + 1;
}
buffer[count] = 0;
if (ch == '#')
{
ch = getDebugChar ();
xmitcsum = hex (ch) << 4;
ch = getDebugChar ();
xmitcsum += hex (ch);
if (checksum != xmitcsum)
{
if (remote_debug)
{
unsigned char buf[16];
mem2hex ((unsigned char *) &checksum, buf, 4, 0);
gdb_error ("Bad checksum: my count = %s, ", buf);
mem2hex ((unsigned char *) &xmitcsum, buf, 4, 0);
gdb_error ("sent count = %s\n", buf);
gdb_error (" -- Bad buffer: \"%s\"\n", buffer);
}
putDebugChar ('-'); /* failed checksum */
}
else
{
putDebugChar ('+'); /* successful transfer */
/* if a sequence char is present, reply the sequence ID */
if (buffer[2] == ':')
{
putDebugChar (buffer[0]);
putDebugChar (buffer[1]);
return &buffer[3];
}
return &buffer[0];
}
}
}
}
/* send the packet in buffer. */
static void
putpacket (unsigned char *buffer)
{
unsigned char checksum;
int count;
char ch;
/* $<packet info>#<checksum>. */
do
{
putDebugChar ('$');
checksum = 0;
count = 0;
while (ch = buffer[count])
{
putDebugChar (ch);
checksum += ch;
count += 1;
}
putDebugChar ('#');
putDebugChar (hexchars[checksum >> 4]);
putDebugChar (hexchars[checksum % 16]);
}
while (getDebugChar () != '+');
}
/* Address of a routine to RTE to if we get a memory fault. */
static void (*volatile mem_fault_routine) () = 0;
static void
set_mem_err (void)
{
mem_err = 1;
}
/* Check the address for safe access ranges. As currently defined,
this routine will reject the "expansion bus" address range(s).
To make those ranges useable, someone must implement code to detect
whether there's anything connected to the expansion bus. */
static int
mem_safe (unsigned char *addr)
{
#define BAD_RANGE_ONE_START ((unsigned char *) 0x600000)
#define BAD_RANGE_ONE_END ((unsigned char *) 0xa00000)
#define BAD_RANGE_TWO_START ((unsigned char *) 0xff680000)
#define BAD_RANGE_TWO_END ((unsigned char *) 0xff800000)
if (addr < BAD_RANGE_ONE_START)
return 1; /* safe */
if (addr < BAD_RANGE_ONE_END)
return 0; /* unsafe */
if (addr < BAD_RANGE_TWO_START)
return 1; /* safe */
if (addr < BAD_RANGE_TWO_END)
return 0; /* unsafe */
}
/* These are separate functions so that they are so short and sweet
that the compiler won't save any registers (if there is a fault
to mem_fault, they won't get restored, so there better not be any
saved). */
static int
get_char (unsigned char *addr)
{
#if 1
if (mem_fault_routine && !mem_safe (addr))
{
mem_fault_routine ();
return 0;
}
#endif
return *addr;
}
static void
set_char (unsigned char *addr, unsigned char val)
{
#if 1
if (mem_fault_routine && !mem_safe (addr))
{
mem_fault_routine ();
return;
}
#endif
*addr = val;
}
/* Convert the memory pointed to by mem into hex, placing result in buf.
Return a pointer to the last char put in buf (null).
If MAY_FAULT is non-zero, then we should set mem_err in response to
a fault; if zero treat a fault like any other fault in the stub. */
static unsigned char *
mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault)
{
int i;
unsigned char ch;
if (may_fault)
mem_fault_routine = set_mem_err;
for (i = 0; i < count; i++)
{
ch = get_char (mem++);
if (may_fault && mem_err)
return (buf);
*buf++ = hexchars[ch >> 4];
*buf++ = hexchars[ch % 16];
}
*buf = 0;
if (may_fault)
mem_fault_routine = 0;
return (buf);
}
/* Convert the hex array pointed to by buf into binary to be placed in mem.
Return a pointer to the character AFTER the last byte written. */
static unsigned char *
hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault)
{
int i;
unsigned char ch;
if (may_fault)
mem_fault_routine = set_mem_err;
for (i = 0; i < count; i++)
{
ch = hex (*buf++) << 4;
ch = ch + hex (*buf++);
set_char (mem++, ch);
if (may_fault && mem_err)
return (mem);
}
if (may_fault)
mem_fault_routine = 0;
return (mem);
}
/* Convert the binary stream in BUF to memory.
Gdb will escape $, #, and the escape char (0x7d).
COUNT is the total number of bytes to write into
memory. */
static unsigned char *
bin2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault)
{
int i;
unsigned char ch;
if (may_fault)
mem_fault_routine = set_mem_err;
for (i = 0; i < count; i++)
{
/* Check for any escaped characters. Be paranoid and
only unescape chars that should be escaped. */
if (*buf == 0x7d)
{
switch (*(buf + 1))
{
case 0x3: /* # */
case 0x4: /* $ */
case 0x5d: /* escape char */
buf++;
*buf |= 0x20;
break;
default:
/* nothing */
break;
}
}
set_char (mem++, *buf++);
if (may_fault && mem_err)
return mem;
}
if (may_fault)
mem_fault_routine = 0;
return mem;
}
/* this function takes the m32r exception vector and attempts to
translate this number into a unix compatible signal value */
static int
computeSignal (int exceptionVector)
{
int sigval;
switch (exceptionVector)
{
case 0:
sigval = 23;
break; /* I/O trap */
case 1:
sigval = 5;
break; /* breakpoint */
case 2:
sigval = 5;
break; /* breakpoint */
case 3:
sigval = 5;
break; /* breakpoint */
case 4:
sigval = 5;
break; /* breakpoint */
case 5:
sigval = 5;
break; /* breakpoint */
case 6:
sigval = 5;
break; /* breakpoint */
case 7:
sigval = 5;
break; /* breakpoint */
case 8:
sigval = 5;
break; /* breakpoint */
case 9:
sigval = 5;
break; /* breakpoint */
case 10:
sigval = 5;
break; /* breakpoint */
case 11:
sigval = 5;
break; /* breakpoint */
case 12:
sigval = 5;
break; /* breakpoint */
case 13:
sigval = 5;
break; /* breakpoint */
case 14:
sigval = 5;
break; /* breakpoint */
case 15:
sigval = 5;
break; /* breakpoint */
case 16:
sigval = 10;
break; /* BUS ERROR (alignment) */
case 17:
sigval = 2;
break; /* INTerrupt */
default:
sigval = 7;
break; /* "software generated" */
}
return (sigval);
}
/**********************************************/
/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
/* RETURN NUMBER OF CHARS PROCESSED */
/**********************************************/
static int
hexToInt (unsigned char **ptr, int *intValue)
{
int numChars = 0;
int hexValue;
*intValue = 0;
while (**ptr)
{
hexValue = hex (**ptr);
if (hexValue >= 0)
{
*intValue = (*intValue << 4) | hexValue;
numChars++;
}
else
break;
(*ptr)++;
}
return (numChars);
}
/*
Table of branch instructions:
10B6 RTE return from trap or exception
1FCr JMP jump
1ECr JL jump and link
7Fxx BRA branch
FFxxxxxx BRA branch (long)
B09rxxxx BNEZ branch not-equal-zero
Br1rxxxx BNE branch not-equal
7Dxx BNC branch not-condition
FDxxxxxx BNC branch not-condition (long)
B0Arxxxx BLTZ branch less-than-zero
B0Crxxxx BLEZ branch less-equal-zero
7Exx BL branch and link
FExxxxxx BL branch and link (long)
B0Drxxxx BGTZ branch greater-than-zero
B0Brxxxx BGEZ branch greater-equal-zero
B08rxxxx BEQZ branch equal-zero
Br0rxxxx BEQ branch equal
7Cxx BC branch condition
FCxxxxxx BC branch condition (long)
*/
static int
isShortBranch (unsigned char *instr)
{
unsigned char instr0 = instr[0] & 0x7F; /* mask off high bit */
if (instr0 == 0x10 && instr[1] == 0xB6) /* RTE */
return 1; /* return from trap or exception */
if (instr0 == 0x1E || instr0 == 0x1F) /* JL or JMP */
if ((instr[1] & 0xF0) == 0xC0)
return 2; /* jump thru a register */
if (instr0 == 0x7C || instr0 == 0x7D || /* BC, BNC, BL, BRA */
instr0 == 0x7E || instr0 == 0x7F)
return 3; /* eight bit PC offset */
return 0;
}
static int
isLongBranch (unsigned char *instr)
{
if (instr[0] == 0xFC || instr[0] == 0xFD || /* BRA, BNC, BL, BC */
instr[0] == 0xFE || instr[0] == 0xFF) /* 24 bit relative */
return 4;
if ((instr[0] & 0xF0) == 0xB0) /* 16 bit relative */
{
if ((instr[1] & 0xF0) == 0x00 || /* BNE, BEQ */
(instr[1] & 0xF0) == 0x10)
return 5;
if (instr[0] == 0xB0) /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ, BEQZ */
if ((instr[1] & 0xF0) == 0x80 || (instr[1] & 0xF0) == 0x90 ||
(instr[1] & 0xF0) == 0xA0 || (instr[1] & 0xF0) == 0xB0 ||
(instr[1] & 0xF0) == 0xC0 || (instr[1] & 0xF0) == 0xD0)
return 6;
}
return 0;
}
/* if address is NOT on a 4-byte boundary, or high-bit of instr is zero,
then it's a 2-byte instruction, else it's a 4-byte instruction. */
#define INSTRUCTION_SIZE(addr) \
((((int) addr & 2) || (((unsigned char *) addr)[0] & 0x80) == 0) ? 2 : 4)
static int
isBranch (unsigned char *instr)
{
if (INSTRUCTION_SIZE (instr) == 2)
return isShortBranch (instr);
else
return isLongBranch (instr);
}
static int
willBranch (unsigned char *instr, int branchCode)
{
switch (branchCode)
{
case 0:
return 0; /* not a branch */
case 1:
return 1; /* RTE */
case 2:
return 1; /* JL or JMP */
case 3: /* BC, BNC, BL, BRA (short) */
case 4: /* BC, BNC, BL, BRA (long) */
switch (instr[0] & 0x0F)
{
case 0xC: /* Branch if Condition Register */
return (registers[CBR] != 0);
case 0xD: /* Branch if NOT Condition Register */
return (registers[CBR] == 0);
case 0xE: /* Branch and Link */
case 0xF: /* Branch (unconditional) */
return 1;
default: /* oops? */
return 0;
}
case 5: /* BNE, BEQ */
switch (instr[1] & 0xF0)
{
case 0x00: /* Branch if r1 equal to r2 */
return (registers[instr[0] & 0x0F] == registers[instr[1] & 0x0F]);
case 0x10: /* Branch if r1 NOT equal to r2 */
return (registers[instr[0] & 0x0F] != registers[instr[1] & 0x0F]);
default: /* oops? */
return 0;
}
case 6: /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ ,BEQZ */
switch (instr[1] & 0xF0)
{
case 0x80: /* Branch if reg equal to zero */
return (registers[instr[1] & 0x0F] == 0);
case 0x90: /* Branch if reg NOT equal to zero */
return (registers[instr[1] & 0x0F] != 0);
case 0xA0: /* Branch if reg less than zero */
return (registers[instr[1] & 0x0F] < 0);
case 0xB0: /* Branch if reg greater or equal to zero */
return (registers[instr[1] & 0x0F] >= 0);
case 0xC0: /* Branch if reg less than or equal to zero */
return (registers[instr[1] & 0x0F] <= 0);
case 0xD0: /* Branch if reg greater than zero */
return (registers[instr[1] & 0x0F] > 0);
default: /* oops? */
return 0;
}
default: /* oops? */
return 0;
}
}
static int
branchDestination (unsigned char *instr, int branchCode)
{
switch (branchCode)
{
default:
case 0: /* not a branch */
return 0;
case 1: /* RTE */
return registers[BPC] & ~3; /* pop BPC into PC */
case 2: /* JL or JMP */
return registers[instr[1] & 0x0F] & ~3; /* jump thru a register */
case 3: /* BC, BNC, BL, BRA (short, 8-bit relative offset) */
return (((int) instr) & ~3) + ((char) instr[1] << 2);
case 4: /* BC, BNC, BL, BRA (long, 24-bit relative offset) */
return ((int) instr +
((((char) instr[1] << 16) | (instr[2] << 8) | (instr[3])) <<
2));
case 5: /* BNE, BEQ (16-bit relative offset) */
case 6: /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ ,BEQZ (ditto) */
return ((int) instr + ((((char) instr[2] << 8) | (instr[3])) << 2));
}
/* An explanatory note: in the last three return expressions, I have
cast the most-significant byte of the return offset to char.
What this accomplishes is sign extension. If the other
less-significant bytes were signed as well, they would get sign
extended too and, if negative, their leading bits would clobber
the bits of the more-significant bytes ahead of them. There are
other ways I could have done this, but sign extension from
odd-sized integers is always a pain. */
}
static void
branchSideEffects (unsigned char *instr, int branchCode)
{
switch (branchCode)
{
case 1: /* RTE */
return; /* I <THINK> this is already handled... */
case 2: /* JL (or JMP) */
case 3: /* BL (or BC, BNC, BRA) */
case 4:
if ((instr[0] & 0x0F) == 0x0E) /* branch/jump and link */
registers[R14] = (registers[PC] & ~3) + 4;
return;
default: /* any other branch has no side effects */
return;
}
}
static struct STEPPING_CONTEXT
{
int stepping; /* true when we've started a single-step */
unsigned long target_addr; /* the instr we're trying to execute */
unsigned long target_size; /* the size of the target instr */
unsigned long noop_addr; /* where we've inserted a no-op, if any */
unsigned long trap1_addr; /* the trap following the target instr */
unsigned long trap2_addr; /* the trap at a branch destination, if any */
unsigned short noop_save; /* instruction overwritten by our no-op */
unsigned short trap1_save; /* instruction overwritten by trap1 */
unsigned short trap2_save; /* instruction overwritten by trap2 */
unsigned short continue_p; /* true if NOT returning to gdb after step */
} stepping;
/* Function: prepare_to_step
Called from handle_exception to prepare the user program to single-step.
Places a trap instruction after the target instruction, with special
extra handling for branch instructions and for instructions in the
second half-word of a word.
Returns: True if we should actually execute the instruction;
False if we are going to emulate executing the instruction,
in which case we simply report to GDB that the instruction
has already been executed. */
#define TRAP1 0x10f1; /* trap #1 instruction */
#define NOOP 0x7000; /* noop instruction */
static unsigned short trap1 = TRAP1;
static unsigned short noop = NOOP;
static int
prepare_to_step (continue_p)
int continue_p; /* if this isn't REALLY a single-step (see below) */
{
unsigned long pc = registers[PC];
int branchCode = isBranch ((unsigned char *) pc);
unsigned char *p;
/* zero out the stepping context
(paranoia -- it should already be zeroed) */
for (p = (unsigned char *) &stepping;
p < ((unsigned char *) &stepping) + sizeof (stepping); p++)
*p = 0;
if (branchCode != 0) /* next instruction is a branch */
{
branchSideEffects ((unsigned char *) pc, branchCode);
if (willBranch ((unsigned char *) pc, branchCode))
registers[PC] = branchDestination ((unsigned char *) pc, branchCode);
else
registers[PC] = pc + INSTRUCTION_SIZE (pc);
return 0; /* branch "executed" -- just notify GDB */
}
else if (((int) pc & 2) != 0) /* "second-slot" instruction */
{
/* insert no-op before pc */
stepping.noop_addr = pc - 2;
stepping.noop_save = *(unsigned short *) stepping.noop_addr;
*(unsigned short *) stepping.noop_addr = noop;
/* insert trap after pc */
stepping.trap1_addr = pc + 2;
stepping.trap1_save = *(unsigned short *) stepping.trap1_addr;
*(unsigned short *) stepping.trap1_addr = trap1;
}
else /* "first-slot" instruction */
{
/* insert trap after pc */
stepping.trap1_addr = pc + INSTRUCTION_SIZE (pc);
stepping.trap1_save = *(unsigned short *) stepping.trap1_addr;
*(unsigned short *) stepping.trap1_addr = trap1;
}
/* "continue_p" means that we are actually doing a continue, and not
being requested to single-step by GDB. Sometimes we have to do
one single-step before continuing, because the PC is on a half-word
boundary. There's no way to simply resume at such an address. */
stepping.continue_p = continue_p;
stepping.stepping = 1; /* starting a single-step */
return 1;
}
/* Function: finish_from_step
Called from handle_exception to finish up when the user program
returns from a single-step. Replaces the instructions that had
been overwritten by traps or no-ops,
Returns: True if we should notify GDB that the target stopped.
False if we only single-stepped because we had to before we
could continue (ie. we were trying to continue at a
half-word boundary). In that case don't notify GDB:
just "continue continuing". */
static int
finish_from_step (void)
{
if (stepping.stepping) /* anything to do? */
{
int continue_p = stepping.continue_p;
unsigned char *p;
if (stepping.noop_addr) /* replace instr "under" our no-op */
*(unsigned short *) stepping.noop_addr = stepping.noop_save;
if (stepping.trap1_addr) /* replace instr "under" our trap */
*(unsigned short *) stepping.trap1_addr = stepping.trap1_save;
if (stepping.trap2_addr) /* ditto our other trap, if any */
*(unsigned short *) stepping.trap2_addr = stepping.trap2_save;
for (p = (unsigned char *) &stepping; /* zero out the stepping context */
p < ((unsigned char *) &stepping) + sizeof (stepping); p++)
*p = 0;
return !(continue_p);
}
else /* we didn't single-step, therefore this must be a legitimate stop */
return 1;
}
struct PSWreg
{ /* separate out the bit flags in the PSW register */
int pad1:16;
int bsm:1;
int bie:1;
int pad2:5;
int bc:1;
int sm:1;
int ie:1;
int pad3:5;
int c:1;
} *psw;
/* Upon entry the value for LR to save has been pushed.
We unpush that so that the value for the stack pointer saved is correct.
Upon entry, all other registers are assumed to have not been modified
since the interrupt/trap occured. */
asm ("
stash_registers:
push r0
push r1
seth r1, #shigh(registers)
add3 r1, r1, #low(registers)
pop r0 ; r1
st r0, @(4,r1)
pop r0 ; r0
st r0, @r1
addi r1, #4 ; only add 4 as subsequent saves are `pre inc'
st r2, @+r1
st r3, @+r1
st r4, @+r1
st r5, @+r1
st r6, @+r1
st r7, @+r1
st r8, @+r1
st r9, @+r1
st r10, @+r1
st r11, @+r1
st r12, @+r1
st r13, @+r1 ; fp
pop r0 ; lr (r14)
st r0, @+r1
st sp, @+r1 ; sp contains right value at this point
mvfc r0, cr0
st r0, @+r1 ; cr0 == PSW
mvfc r0, cr1
st r0, @+r1 ; cr1 == CBR
mvfc r0, cr2
st r0, @+r1 ; cr2 == SPI
mvfc r0, cr3
st r0, @+r1 ; cr3 == SPU
mvfc r0, cr6
st r0, @+r1 ; cr6 == BPC
st r0, @+r1 ; PC == BPC
mvfaclo r0
st r0, @+r1 ; ACCL
mvfachi r0
st r0, @+r1 ; ACCH
jmp lr");
/* C routine to clean up what stash_registers did.
It is called after calling stash_registers.
This is separate from stash_registers as we want to do this in C
but doing stash_registers in C isn't straightforward. */
static void
cleanup_stash (void)
{
psw = (struct PSWreg *) ®isters[PSW]; /* fields of PSW register */
psw->sm = psw->bsm; /* fix up pre-trap values of psw fields */
psw->ie = psw->bie;
psw->c = psw->bc;
registers[CBR] = psw->bc; /* fix up pre-trap "C" register */
#if 0 /* FIXME: Was in previous version. Necessary?
(Remember that we use the "rte" insn to return from the
trap/interrupt so the values of bsm, bie, bc are important. */
psw->bsm = psw->bie = psw->bc = 0; /* zero post-trap values */
#endif
/* FIXME: Copied from previous version. This can probably be deleted
since methinks stash_registers has already done this. */
registers[PC] = registers[BPC]; /* pre-trap PC */
/* FIXME: Copied from previous version. Necessary? */
if (psw->sm) /* copy R15 into (psw->sm ? SPU : SPI) */
registers[SPU] = registers[R15];
else
registers[SPI] = registers[R15];
}
asm ("
restore_and_return:
seth r0, #shigh(registers+8)
add3 r0, r0, #low(registers+8)
ld r2, @r0+ ; restore r2
ld r3, @r0+ ; restore r3
ld r4, @r0+ ; restore r4
ld r5, @r0+ ; restore r5
ld r6, @r0+ ; restore r6
ld r7, @r0+ ; restore r7
ld r8, @r0+ ; restore r8
ld r9, @r0+ ; restore r9
ld r10, @r0+ ; restore r10
ld r11, @r0+ ; restore r11
ld r12, @r0+ ; restore r12
ld r13, @r0+ ; restore r13
ld r14, @r0+ ; restore r14
ld r15, @r0+ ; restore r15
ld r1, @r0+ ; restore cr0 == PSW
mvtc r1, cr0
ld r1, @r0+ ; restore cr1 == CBR (no-op, because it's read only)
mvtc r1, cr1
ld r1, @r0+ ; restore cr2 == SPI
mvtc r1, cr2
ld r1, @r0+ ; restore cr3 == SPU
mvtc r1, cr3
addi r0, #4 ; skip BPC
ld r1, @r0+ ; restore cr6 (BPC) == PC
mvtc r1, cr6
ld r1, @r0+ ; restore ACCL
mvtaclo r1
ld r1, @r0+ ; restore ACCH
mvtachi r1
seth r0, #shigh(registers)
add3 r0, r0, #low(registers)
ld r1, @(4,r0) ; restore r1
ld r0, @r0 ; restore r0
rte");
/* General trap handler, called after the registers have been stashed.
NUM is the trap/exception number. */
static void
process_exception (int num)
{
cleanup_stash ();
asm volatile ("
seth r1, #shigh(stackPtr)
add3 r1, r1, #low(stackPtr)
ld r15, @r1 ; setup local stack (protect user stack)
mv r0, %0
bl handle_exception
bl restore_and_return"::"r" (num):"r0", "r1");
}
void _catchException0 ();
asm ("
_catchException0:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #0
bl process_exception");
void _catchException1 ();
asm ("
_catchException1:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
bl cleanup_stash
seth r1, #shigh(stackPtr)
add3 r1, r1, #low(stackPtr)
ld r15, @r1 ; setup local stack (protect user stack)
seth r1, #shigh(registers + 21*4) ; PC
add3 r1, r1, #low(registers + 21*4)
ld r0, @r1
addi r0, #-4 ; back up PC for breakpoint trap.
st r0, @r1 ; FIXME: what about bp in right slot?
ldi r0, #1
bl handle_exception
bl restore_and_return");
void _catchException2 ();
asm ("
_catchException2:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #2
bl process_exception");
void _catchException3 ();
asm ("
_catchException3:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #3
bl process_exception");
void _catchException4 ();
asm ("
_catchException4:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #4
bl process_exception");
void _catchException5 ();
asm ("
_catchException5:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #5
bl process_exception");
void _catchException6 ();
asm ("
_catchException6:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #6
bl process_exception");
void _catchException7 ();
asm ("
_catchException7:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #7
bl process_exception");
void _catchException8 ();
asm ("
_catchException8:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #8
bl process_exception");
void _catchException9 ();
asm ("
_catchException9:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #9
bl process_exception");
void _catchException10 ();
asm ("
_catchException10:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #10
bl process_exception");
void _catchException11 ();
asm ("
_catchException11:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #11
bl process_exception");
void _catchException12 ();
asm ("
_catchException12:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #12
bl process_exception");
void _catchException13 ();
asm ("
_catchException13:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #13
bl process_exception");
void _catchException14 ();
asm ("
_catchException14:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #14
bl process_exception");
void _catchException15 ();
asm ("
_catchException15:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #15
bl process_exception");
void _catchException16 ();
asm ("
_catchException16:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #16
bl process_exception");
void _catchException17 ();
asm ("
_catchException17:
push lr
bl stash_registers
; Note that at this point the pushed value of `lr' has been popped
ldi r0, #17
bl process_exception");
/* this function is used to set up exception handlers for tracing and
breakpoints */
void
set_debug_traps (void)
{
/* extern void remcomHandler(); */
int i;
for (i = 0; i < 18; i++) /* keep a copy of old vectors */
if (save_vectors[i] == 0) /* only copy them the first time */
save_vectors[i] = getExceptionHandler (i);
stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1];
exceptionHandler (0, _catchException0);
exceptionHandler (1, _catchException1);
exceptionHandler (2, _catchException2);
exceptionHandler (3, _catchException3);
exceptionHandler (4, _catchException4);
exceptionHandler (5, _catchException5);
exceptionHandler (6, _catchException6);
exceptionHandler (7, _catchException7);
exceptionHandler (8, _catchException8);
exceptionHandler (9, _catchException9);
exceptionHandler (10, _catchException10);
exceptionHandler (11, _catchException11);
exceptionHandler (12, _catchException12);
exceptionHandler (13, _catchException13);
exceptionHandler (14, _catchException14);
exceptionHandler (15, _catchException15);
exceptionHandler (16, _catchException16);
/* exceptionHandler (17, _catchException17); */
initialized = 1;
}
/* This function will generate a breakpoint exception. It is used at the
beginning of a program to sync up with a debugger and can be used
otherwise as a quick means to stop program execution and "break" into
the debugger. */
#define BREAKPOINT() asm volatile (" trap #2");
void
breakpoint (void)
{
if (initialized)
BREAKPOINT ();
}
/* STDOUT section:
Stuff pertaining to simulating stdout by sending chars to gdb to be echoed.
Functions: gdb_putchar(char ch)
gdb_puts(char *str)
gdb_write(char *str, int len)
gdb_error(char *format, char *parm)
*/
/* Function: gdb_putchar(int)
Make gdb write a char to stdout.
Returns: the char */
static int
gdb_putchar (int ch)
{
char buf[4];
buf[0] = 'O';
buf[1] = hexchars[ch >> 4];
buf[2] = hexchars[ch & 0x0F];
buf[3] = 0;
putpacket (buf);
return ch;
}
/* Function: gdb_write(char *, int)
Make gdb write n bytes to stdout (not assumed to be null-terminated).
Returns: number of bytes written */
static int
gdb_write (char *data, int len)
{
char *buf, *cpy;
int i;
buf = remcomOutBuffer;
buf[0] = 'O';
i = 0;
while (i < len)
{
for (cpy = buf + 1;
i < len && cpy < buf + sizeof (remcomOutBuffer) - 3; i++)
{
*cpy++ = hexchars[data[i] >> 4];
*cpy++ = hexchars[data[i] & 0x0F];
}
*cpy = 0;
putpacket (buf);
}
return len;
}
/* Function: gdb_puts(char *)
Make gdb write a null-terminated string to stdout.
Returns: the length of the string */
static int
gdb_puts (char *str)
{
return gdb_write (str, strlen (str));
}
/* Function: gdb_error(char *, char *)
Send an error message to gdb's stdout.
First string may have 1 (one) optional "%s" in it, which
will cause the optional second string to be inserted. */
static void
gdb_error (char *format, char *parm)
{
char buf[400], *cpy;
int len;
if (remote_debug)
{
if (format && *format)
len = strlen (format);
else
return; /* empty input */
if (parm && *parm)
len += strlen (parm);
for (cpy = buf; *format;)
{
if (format[0] == '%' && format[1] == 's') /* include second string */
{
format += 2; /* advance two chars instead of just one */
while (parm && *parm)
*cpy++ = *parm++;
}
else
*cpy++ = *format++;
}
*cpy = '\0';
gdb_puts (buf);
}
}
static unsigned char *
strcpy (unsigned char *dest, const unsigned char *src)
{
unsigned char *ret = dest;
if (dest && src)
{
while (*src)
*dest++ = *src++;
*dest = 0;
}
return ret;
}
static int
strlen (const unsigned char *src)
{
int ret;
for (ret = 0; *src; src++)
ret++;
return ret;
}
#if 0
void
exit (code)
int code;
{
_exit (code);
}
int
atexit (void *p)
{
return 0;
}
void
abort (void)
{
_exit (1);
}
#endif
[-- Attachment #4: m32r-rom.c --]
[-- Type: application/octet-stream, Size: 22341 bytes --]
/* Remote debugging interface to m32r and mon2000 ROM monitors for GDB,
the GNU debugger.
Copyright 1996, 1997, 1998, 1999, 2000, 2001
Free Software Foundation, Inc.
Adapted by Michael Snyder of Cygnus Support.
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. */
/* This module defines communication with the Renesas m32r monitor */
#include "defs.h"
#include "gdbcore.h"
#include "target.h"
#include "monitor.h"
#include "serial.h"
#include "symtab.h"
#include "command.h"
#include "gdbcmd.h"
#include "symfile.h" /* for generic load */
#include <time.h> /* for time_t */
#include "gdb_string.h"
#include "objfiles.h" /* for ALL_OBJFILES etc. */
#include "inferior.h" /* for write_pc() */
#include <ctype.h>
#include "regcache.h"
extern void report_transfer_performance (unsigned long, time_t, time_t);
/*
* All this stuff just to get my host computer's IP address!
*/
#include <sys/types.h>
#include <netdb.h> /* for hostent */
#include <netinet/in.h> /* for struct in_addr */
#if 1
#include <arpa/inet.h> /* for inet_ntoa */
#endif
static char *board_addr; /* user-settable IP address for M32R-EVA */
static char *server_addr; /* user-settable IP address for gdb host */
static char *download_path; /* user-settable path for SREC files */
/* REGNUM */
#define PSW_REGNUM 16
#define SPI_REGNUM 18
#define SPU_REGNUM 19
#define ACCL_REGNUM 22
#define ACCH_REGNUM 23
/*
* Function: m32r_load_1 (helper function)
*/
static void
m32r_load_section (bfd *abfd, asection *s, void *obj)
{
unsigned int *data_count = obj;
if (s->flags & SEC_LOAD)
{
bfd_size_type section_size = bfd_section_size (abfd, s);
bfd_vma section_base = bfd_section_lma (abfd, s);
unsigned int buffer, i;
*data_count += section_size;
printf_filtered ("Loading section %s, size 0x%lx lma ",
bfd_section_name (abfd, s), section_size);
print_address_numeric (section_base, 1, gdb_stdout);
printf_filtered ("\n");
gdb_flush (gdb_stdout);
monitor_printf ("%s mw\r", paddr_nz (section_base));
for (i = 0; i < section_size; i += 4)
{
QUIT;
monitor_expect (" -> ", NULL, 0);
bfd_get_section_contents (abfd, s, (char *) &buffer, i, 4);
monitor_printf ("%x\n", buffer);
}
monitor_expect (" -> ", NULL, 0);
monitor_printf ("q\n");
monitor_expect_prompt (NULL, 0);
}
}
static int
m32r_load_1 (void *dummy)
{
int data_count = 0;
bfd_map_over_sections ((bfd *) dummy, m32r_load_section, &data_count);
return data_count;
}
/*
* Function: m32r_load (an alternate way to load)
*/
static void
m32r_load (char *filename, int from_tty)
{
bfd *abfd;
asection *s;
unsigned int i, data_count = 0;
time_t start_time, end_time; /* for timing of download */
if (filename == NULL || filename[0] == 0)
filename = get_exec_file (1);
abfd = bfd_openr (filename, 0);
if (!abfd)
error ("Unable to open file %s\n", filename);
if (bfd_check_format (abfd, bfd_object) == 0)
error ("File is not an object file\n");
start_time = time (NULL);
#if 0
for (s = abfd->sections; s; s = s->next)
if (s->flags & SEC_LOAD)
{
bfd_size_type section_size = bfd_section_size (abfd, s);
bfd_vma section_base = bfd_section_vma (abfd, s);
unsigned int buffer;
data_count += section_size;
printf_filtered ("Loading section %s, size 0x%lx vma ",
bfd_section_name (abfd, s), section_size);
print_address_numeric (section_base, 1, gdb_stdout);
printf_filtered ("\n");
gdb_flush (gdb_stdout);
monitor_printf ("%x mw\r", section_base);
for (i = 0; i < section_size; i += 4)
{
monitor_expect (" -> ", NULL, 0);
bfd_get_section_contents (abfd, s, (char *) &buffer, i, 4);
monitor_printf ("%x\n", buffer);
}
monitor_expect (" -> ", NULL, 0);
monitor_printf ("q\n");
monitor_expect_prompt (NULL, 0);
}
#else
if (!(catch_errors (m32r_load_1, abfd, "Load aborted!\n", RETURN_MASK_ALL)))
{
monitor_printf ("q\n");
return;
}
#endif
end_time = time (NULL);
printf_filtered ("Start address 0x%lx\n", bfd_get_start_address (abfd));
report_transfer_performance (data_count, start_time, end_time);
/* Finally, make the PC point at the start address */
if (exec_bfd)
write_pc (bfd_get_start_address (exec_bfd));
inferior_ptid = null_ptid; /* No process now */
/* This is necessary because many things were based on the PC at the
time that we attached to the monitor, which is no longer valid
now that we have loaded new code (and just changed the PC).
Another way to do this might be to call normal_stop, except that
the stack may not be valid, and things would get horribly
confused... */
clear_symtab_users ();
}
static void
m32r_load_gen (char *filename, int from_tty)
{
generic_load (filename, from_tty);
}
static void m32r_open (char *args, int from_tty);
static void mon2000_open (char *args, int from_tty);
/* This array of registers needs to match the indexes used by GDB. The
whole reason this exists is because the various ROM monitors use
different names than GDB does, and don't support all the registers
either. So, typing "info reg sp" becomes an "A7". */
static char *m32r_regnames[] =
{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"psw", "cbr", "spi", "spu", "bpc", "pc", "accl", "acch",
};
static void
m32r_supply_register (char *regname, int regnamelen, char *val, int vallen)
{
int regno;
int num_regs = sizeof (m32r_regnames) / sizeof (m32r_regnames[0]);
for (regno = 0; regno < num_regs; regno++)
if (strncmp (regname, m32r_regnames[regno], regnamelen) == 0)
break;
if (regno >= num_regs)
return; /* no match */
if (regno == ACCL_REGNUM)
{ /* special handling for 64-bit acc reg */
monitor_supply_register (ACCH_REGNUM, val);
val = strchr (val, ':'); /* skip past ':' to get 2nd word */
if (val != NULL)
monitor_supply_register (ACCL_REGNUM, val + 1);
}
else
{
monitor_supply_register (regno, val);
if (regno == PSW_REGNUM)
{
unsigned long psw = strtoul (val, NULL, 16);
char *zero = "00000000", *one = "00000001";
#ifdef SM_REGNUM
/* Stack mode bit */
monitor_supply_register (SM_REGNUM, (psw & 0x80) ? one : zero);
#endif
#ifdef BSM_REGNUM
/* Backup stack mode bit */
monitor_supply_register (BSM_REGNUM, (psw & 0x8000) ? one : zero);
#endif
#ifdef IE_REGNUM
/* Interrupt enable bit */
monitor_supply_register (IE_REGNUM, (psw & 0x40) ? one : zero);
#endif
#ifdef BIE_REGNUM
/* Backup interrupt enable bit */
monitor_supply_register (BIE_REGNUM, (psw & 0x4000) ? one : zero);
#endif
#ifdef COND_REGNUM
/* Condition bit (carry etc.) */
monitor_supply_register (COND_REGNUM, (psw & 0x1) ? one : zero);
#endif
#ifdef CBR_REGNUM
monitor_supply_register (CBR_REGNUM, (psw & 0x1) ? one : zero);
#endif
#ifdef BPC_REGNUM
monitor_supply_register (BPC_REGNUM, zero); /* KLUDGE: (???????) */
#endif
#ifdef BCARRY_REGNUM
monitor_supply_register (BCARRY_REGNUM, zero); /* KLUDGE: (??????) */
#endif
}
if (regno == SPI_REGNUM || regno == SPU_REGNUM)
{ /* special handling for stack pointer (spu or spi) */
unsigned long stackmode = read_register (PSW_REGNUM) & 0x80;
if (regno == SPI_REGNUM && !stackmode) /* SP == SPI */
monitor_supply_register (SP_REGNUM, val);
else if (regno == SPU_REGNUM && stackmode) /* SP == SPU */
monitor_supply_register (SP_REGNUM, val);
}
}
}
/* m32r RevC board monitor */
static struct target_ops m32r_ops;
static char *m32r_inits[] = { "\r", NULL };
static struct monitor_ops m32r_cmds;
static void
init_m32r_cmds (void)
{
m32r_cmds.flags = MO_CLR_BREAK_USES_ADDR | MO_REGISTER_VALUE_FIRST;
m32r_cmds.init = m32r_inits; /* Init strings */
m32r_cmds.cont = "go\r"; /* continue command */
m32r_cmds.step = "step\r"; /* single step */
m32r_cmds.stop = NULL; /* interrupt command */
m32r_cmds.set_break = "%x +bp\r"; /* set a breakpoint */
m32r_cmds.clr_break = "%x -bp\r"; /* clear a breakpoint */
m32r_cmds.clr_all_break = "bpoff\r"; /* clear all breakpoints */
m32r_cmds.fill = "%x %x %x fill\r"; /* fill (start length val) */
m32r_cmds.setmem.cmdb = "%x 1 %x fill\r"; /* setmem.cmdb (addr, value) */
m32r_cmds.setmem.cmdw = "%x 1 %x fillh\r"; /* setmem.cmdw (addr, value) */
m32r_cmds.setmem.cmdl = "%x 1 %x fillw\r"; /* setmem.cmdl (addr, value) */
m32r_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */
m32r_cmds.setmem.resp_delim = NULL; /* setmem.resp_delim */
m32r_cmds.setmem.term = NULL; /* setmem.term */
m32r_cmds.setmem.term_cmd = NULL; /* setmem.term_cmd */
m32r_cmds.getmem.cmdb = "%x %x dump\r"; /* getmem.cmdb (addr, len) */
m32r_cmds.getmem.cmdw = NULL; /* getmem.cmdw (addr, len) */
m32r_cmds.getmem.cmdl = NULL; /* getmem.cmdl (addr, len) */
m32r_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, len) */
m32r_cmds.getmem.resp_delim = ": "; /* getmem.resp_delim */
m32r_cmds.getmem.term = NULL; /* getmem.term */
m32r_cmds.getmem.term_cmd = NULL; /* getmem.term_cmd */
m32r_cmds.setreg.cmd = "%x to %%%s\r"; /* setreg.cmd (name, value) */
m32r_cmds.setreg.resp_delim = NULL; /* setreg.resp_delim */
m32r_cmds.setreg.term = NULL; /* setreg.term */
m32r_cmds.setreg.term_cmd = NULL; /* setreg.term_cmd */
m32r_cmds.getreg.cmd = NULL; /* getreg.cmd (name) */
m32r_cmds.getreg.resp_delim = NULL; /* getreg.resp_delim */
m32r_cmds.getreg.term = NULL; /* getreg.term */
m32r_cmds.getreg.term_cmd = NULL; /* getreg.term_cmd */
m32r_cmds.dump_registers = ".reg\r"; /* dump_registers */
m32r_cmds.register_pattern = "\\(\\w+\\) += \\([0-9a-fA-F]+\\b\\)"; /* register_pattern */
m32r_cmds.supply_register = m32r_supply_register; /* supply_register */
m32r_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */
m32r_cmds.load = NULL; /* download command */
m32r_cmds.loadresp = NULL; /* load response */
m32r_cmds.prompt = "ok "; /* monitor command prompt */
m32r_cmds.line_term = "\r"; /* end-of-line terminator */
m32r_cmds.cmd_end = NULL; /* optional command terminator */
m32r_cmds.target = &m32r_ops; /* target operations */
m32r_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */
m32r_cmds.regnames = m32r_regnames; /* registers names */
m32r_cmds.magic = MONITOR_OPS_MAGIC; /* magic */
} /* init_m32r_cmds */
static void
m32r_open (char *args, int from_tty)
{
monitor_open (args, &m32r_cmds, from_tty);
}
/* Mon2000 monitor (MSA2000 board) */
static struct target_ops mon2000_ops;
static struct monitor_ops mon2000_cmds;
static void
init_mon2000_cmds (void)
{
mon2000_cmds.flags = MO_CLR_BREAK_USES_ADDR | MO_REGISTER_VALUE_FIRST;
mon2000_cmds.init = m32r_inits; /* Init strings */
mon2000_cmds.cont = "go\r"; /* continue command */
mon2000_cmds.step = "step\r"; /* single step */
mon2000_cmds.stop = NULL; /* interrupt command */
mon2000_cmds.set_break = "%x +bp\r"; /* set a breakpoint */
mon2000_cmds.clr_break = "%x -bp\r"; /* clear a breakpoint */
mon2000_cmds.clr_all_break = "bpoff\r"; /* clear all breakpoints */
mon2000_cmds.fill = "%x %x %x fill\r"; /* fill (start length val) */
mon2000_cmds.setmem.cmdb = "%x 1 %x fill\r"; /* setmem.cmdb (addr, value) */
mon2000_cmds.setmem.cmdw = "%x 1 %x fillh\r"; /* setmem.cmdw (addr, value) */
mon2000_cmds.setmem.cmdl = "%x 1 %x fillw\r"; /* setmem.cmdl (addr, value) */
mon2000_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */
mon2000_cmds.setmem.resp_delim = NULL; /* setmem.resp_delim */
mon2000_cmds.setmem.term = NULL; /* setmem.term */
mon2000_cmds.setmem.term_cmd = NULL; /* setmem.term_cmd */
mon2000_cmds.getmem.cmdb = "%x %x dump\r"; /* getmem.cmdb (addr, len) */
mon2000_cmds.getmem.cmdw = NULL; /* getmem.cmdw (addr, len) */
mon2000_cmds.getmem.cmdl = NULL; /* getmem.cmdl (addr, len) */
mon2000_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, len) */
mon2000_cmds.getmem.resp_delim = ": "; /* getmem.resp_delim */
mon2000_cmds.getmem.term = NULL; /* getmem.term */
mon2000_cmds.getmem.term_cmd = NULL; /* getmem.term_cmd */
mon2000_cmds.setreg.cmd = "%x to %%%s\r"; /* setreg.cmd (name, value) */
mon2000_cmds.setreg.resp_delim = NULL; /* setreg.resp_delim */
mon2000_cmds.setreg.term = NULL; /* setreg.term */
mon2000_cmds.setreg.term_cmd = NULL; /* setreg.term_cmd */
mon2000_cmds.getreg.cmd = NULL; /* getreg.cmd (name) */
mon2000_cmds.getreg.resp_delim = NULL; /* getreg.resp_delim */
mon2000_cmds.getreg.term = NULL; /* getreg.term */
mon2000_cmds.getreg.term_cmd = NULL; /* getreg.term_cmd */
mon2000_cmds.dump_registers = ".reg\r"; /* dump_registers */
mon2000_cmds.register_pattern = "\\(\\w+\\) += \\([0-9a-fA-F]+\\b\\)"; /* register_pattern */
mon2000_cmds.supply_register = m32r_supply_register; /* supply_register */
mon2000_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */
mon2000_cmds.load = NULL; /* download command */
mon2000_cmds.loadresp = NULL; /* load response */
mon2000_cmds.prompt = "Mon2000>"; /* monitor command prompt */
mon2000_cmds.line_term = "\r"; /* end-of-line terminator */
mon2000_cmds.cmd_end = NULL; /* optional command terminator */
mon2000_cmds.target = &mon2000_ops; /* target operations */
mon2000_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */
mon2000_cmds.regnames = m32r_regnames; /* registers names */
mon2000_cmds.magic = MONITOR_OPS_MAGIC; /* magic */
} /* init_mon2000_cmds */
static void
mon2000_open (char *args, int from_tty)
{
monitor_open (args, &mon2000_cmds, from_tty);
}
/* Function: set_board_address
Tell the BootOne monitor what it's ethernet IP address is. */
static void
m32r_set_board_address (char *args, int from_tty)
{
int resp_len;
char buf[1024];
if (args && *args)
{
monitor_printf ("ulip %s\n", args);
resp_len = monitor_expect_prompt (buf, sizeof (buf));
/* now parse the result for success */
}
else
error ("Requires argument (IP address for M32R-EVA board)");
}
/* Function: set_server_address
Tell the BootOne monitor what gdb's ethernet IP address is. */
static void
m32r_set_server_address (char *args, int from_tty)
{
int resp_len;
char buf[1024];
if (args && *args)
{
monitor_printf ("uhip %s\n", args);
resp_len = monitor_expect_prompt (buf, sizeof (buf));
/* now parse the result for success */
}
else
error ("Requires argument (IP address of GDB's host computer)");
}
/* Function: set_download_path
Tell the BootOne monitor the default path for downloadable SREC files. */
static void
m32r_set_download_path (char *args, int from_tty)
{
int resp_len;
char buf[1024];
if (args && *args)
{
monitor_printf ("up %s\n", args);
resp_len = monitor_expect_prompt (buf, sizeof (buf));
/* now parse the result for success */
}
else
error ("Requires argument (default path for downloadable SREC files)");
}
static void
m32r_upload_command (char *args, int from_tty)
{
bfd *abfd;
asection *s;
time_t start_time, end_time; /* for timing of download */
int resp_len, data_count = 0;
char buf[1024];
struct hostent *hostent;
struct in_addr inet_addr;
/* first check to see if there's an ethernet port! */
monitor_printf ("ust\r");
resp_len = monitor_expect_prompt (buf, sizeof (buf));
if (!strchr (buf, ':'))
error ("No ethernet connection!");
if (board_addr == 0)
{
/* scan second colon in the output from the "ust" command */
char *myIPaddress = strchr (strchr (buf, ':') + 1, ':') + 1;
while (isspace (*myIPaddress))
myIPaddress++;
if (!strncmp (myIPaddress, "0.0.", 4)) /* empty */
error
("Please use 'set board-address' to set the M32R-EVA board's IP address.");
if (strchr (myIPaddress, '('))
*(strchr (myIPaddress, '(')) = '\0'; /* delete trailing junk */
board_addr = xstrdup (myIPaddress);
}
if (server_addr == 0)
{
buf[0] = 0;
gethostname (buf, sizeof (buf));
if (buf[0] != 0)
hostent = gethostbyname (buf);
if (hostent != 0)
{
#if 1
memcpy (&inet_addr.s_addr, hostent->h_addr,
sizeof (inet_addr.s_addr));
server_addr = (char *) inet_ntoa (inet_addr);
#else
server_addr = (char *) inet_ntoa (hostent->h_addr);
#endif
}
if (server_addr == 0) /* failed? */
error
("Need to know gdb host computer's IP address (use 'set server-address')");
}
if (args == 0 || args[0] == 0) /* no args: upload the current file */
args = get_exec_file (1);
if (args[0] != '/' && download_path == 0)
{
if (current_directory)
download_path = xstrdup (current_directory);
else
error
("Need to know default download path (use 'set download-path')");
}
start_time = time (NULL);
monitor_printf ("uhip %s\r", server_addr);
resp_len = monitor_expect_prompt (buf, sizeof (buf)); /* parse result? */
monitor_printf ("ulip %s\r", board_addr);
resp_len = monitor_expect_prompt (buf, sizeof (buf)); /* parse result? */
if (args[0] != '/')
monitor_printf ("up %s\r", download_path); /* use default path */
else
monitor_printf ("up\r"); /* rooted filename/path */
resp_len = monitor_expect_prompt (buf, sizeof (buf)); /* parse result? */
if (strrchr (args, '.') && !strcmp (strrchr (args, '.'), ".srec"))
monitor_printf ("ul %s\r", args);
else /* add ".srec" suffix */
monitor_printf ("ul %s.srec\r", args);
resp_len = monitor_expect_prompt (buf, sizeof (buf)); /* parse result? */
if (buf[0] == 0 || strstr (buf, "complete") == 0)
error
("Upload file not found: %s.srec\nCheck IP addresses and download path.",
args);
else
printf_filtered (" -- Ethernet load complete.\n");
end_time = time (NULL);
abfd = bfd_openr (args, 0);
if (abfd != NULL)
{ /* Download is done -- print section statistics */
if (bfd_check_format (abfd, bfd_object) == 0)
{
printf_filtered ("File is not an object file\n");
}
for (s = abfd->sections; s; s = s->next)
if (s->flags & SEC_LOAD)
{
bfd_size_type section_size = bfd_section_size (abfd, s);
bfd_vma section_base = bfd_section_lma (abfd, s);
unsigned int buffer;
data_count += section_size;
printf_filtered ("Loading section %s, size 0x%lx lma ",
bfd_section_name (abfd, s), section_size);
print_address_numeric (section_base, 1, gdb_stdout);
printf_filtered ("\n");
gdb_flush (gdb_stdout);
}
/* Finally, make the PC point at the start address */
write_pc (bfd_get_start_address (abfd));
report_transfer_performance (data_count, start_time, end_time);
printf_filtered ("Start address 0x%lx\n", bfd_get_start_address (abfd));
}
inferior_ptid = null_ptid; /* No process now */
/* This is necessary because many things were based on the PC at the
time that we attached to the monitor, which is no longer valid
now that we have loaded new code (and just changed the PC).
Another way to do this might be to call normal_stop, except that
the stack may not be valid, and things would get horribly
confused... */
clear_symtab_users ();
}
void
_initialize_m32r_rom (void)
{
/* Initialize m32r RevC monitor target */
init_m32r_cmds ();
init_monitor_ops (&m32r_ops);
m32r_ops.to_shortname = "m32r";
m32r_ops.to_longname = "m32r monitor";
m32r_ops.to_load = m32r_load_gen; /* monitor lacks a download command */
m32r_ops.to_doc = "Debug via the m32r monitor.\n\
Specify the serial device it is connected to (e.g. /dev/ttya).";
m32r_ops.to_open = m32r_open;
add_target (&m32r_ops);
/* Initialize mon2000 monitor target */
init_mon2000_cmds ();
init_monitor_ops (&mon2000_ops);
mon2000_ops.to_shortname = "mon2000";
mon2000_ops.to_longname = "Mon2000 monitor";
mon2000_ops.to_load = m32r_load_gen; /* monitor lacks a download command */
mon2000_ops.to_doc = "Debug via the Mon2000 monitor.\n\
Specify the serial device it is connected to (e.g. /dev/ttya).";
mon2000_ops.to_open = mon2000_open;
add_target (&mon2000_ops);
add_show_from_set
(add_set_cmd ("download-path", class_obscure, var_string,
(char *) &download_path,
"Set the default path for downloadable SREC files.",
&setlist), &showlist);
add_show_from_set
(add_set_cmd ("board-address", class_obscure, var_string,
(char *) &board_addr,
"Set IP address for M32R-EVA target board.",
&setlist), &showlist);
add_show_from_set
(add_set_cmd ("server-address", class_obscure, var_string,
(char *) &server_addr,
"Set IP address for download server (GDB's host computer).",
&setlist), &showlist);
add_com ("upload", class_obscure, m32r_upload_command,
"Upload the srec file via the monitor's Ethernet upload capability.");
add_com ("tload", class_obscure, m32r_load, "test upload command.");
}
[-- Attachment #5: m32r.mt --]
[-- Type: application/octet-stream, Size: 139 bytes --]
# Target: Renesas m32r processor
TDEPFILES= m32r-tdep.o monitor.o m32r-rom.o dsrec.o
SIM_OBS = remote-sim.o
SIM = ../sim/m32r/libsim.a
[-- Attachment #6: diffs.dat --]
[-- Type: application/octet-stream, Size: 1209 bytes --]
diff -Naur insight-20030703.orig/src/configure insight-20030703/src/configure
--- insight-20030703.orig/src/configure Sat Jun 28 02:34:33 2003
+++ insight-20030703/src/configure Fri Jul 4 09:17:15 2003
@@ -1259,9 +1259,6 @@
i[3456789]86-*-beos*)
noconfigdirs="$noconfigdirs gdb target-newlib target-libgloss ${libgcj}"
;;
- m32r-*-*)
- noconfigdirs="$noconfigdirs ${libgcj} gdb"
- ;;
m68hc11-*-*|m6811-*-*|m68hc12-*-*|m6812-*-*)
noconfigdirs="$noconfigdirs target-libiberty target-libstdc++-v3 ${libgcj}"
;;
diff -Naur insight-20030703.orig/src/gdb/configure.tgt insight-20030703/src/gdb/configure.tgt
--- insight-20030703.orig/src/gdb/configure.tgt Sat Jun 14 02:49:49 2003
+++ insight-20030703/src/gdb/configure.tgt Fri Jul 4 09:17:15 2003
@@ -113,7 +113,7 @@
;;
ia64*-*-*) gdb_target=ia64 ;;
-# OBSOLETE m32r-*-elf*) gdb_target=m32r ;;
+m32r-*-*) gdb_target=m32r ;;
m68hc11*-*-*|m6811*-*-*) gdb_target=m68hc11 ;;
@@ -264,6 +264,7 @@
case "${gdb_target}" in
d10v) gdb_multi_arch=yes ;;
+m32r) gdb_multi_arch=yes ;;
m68hc11) gdb_multi_arch=yes ;;
mn10300) gdb_multi_arch=yes ;;
x86-64linux) gdb_multi_arch=yes ;;
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH] revised m32r target
2003-07-11 7:15 ` Kei Sakamoto
@ 2003-07-11 13:31 ` Andrew Cagney
2003-07-21 18:49 ` Andrew Cagney
1 sibling, 0 replies; 8+ messages in thread
From: Andrew Cagney @ 2003-07-11 13:31 UTC (permalink / raw)
To: Kei Sakamoto, Alexandre Oliva; +Cc: gdb-patches
Its in my queue. Before the am33 changes from alex, but after the
dwarf2 cfi changes. Unless another global maintainer looks at it first,
that is. I'm guessing the start of next week (which for you would be
near to the middle).
Andrew
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] revised m32r target
2003-07-11 7:15 ` Kei Sakamoto
2003-07-11 13:31 ` Andrew Cagney
@ 2003-07-21 18:49 ` Andrew Cagney
2003-07-22 5:00 ` Kei Sakamoto
1 sibling, 1 reply; 8+ messages in thread
From: Andrew Cagney @ 2003-07-21 18:49 UTC (permalink / raw)
To: Kei Sakamoto; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 207 bytes --]
Kei,
I've checked in the .c files, as posted. Not bad, not bad at all.
Can you just see how many of the attached can also be fixed? I'll then
look at enabling it and pulling it into the 6 branch.
Andrew
[-- Attachment #2: x --]
[-- Type: text/plain, Size: 1926 bytes --]
m32r-rom.c:43: warning: code: Do not use `extern' in .c files
m32r-rom.c:267: warning: obsolete: Replace read_register() with regcache_read() et.al.
m32r-rom.c:613: warning: obsolete: Do not use add_show_from_set(), instead use add_setshow...() (add_show_from_set() is very I18N unfriendly - see PR gdb/434)
m32r-rom.c:619: warning: obsolete: Do not use add_show_from_set(), instead use add_setshow...() (add_show_from_set() is very I18N unfriendly - see PR gdb/434)
m32r-rom.c:625: warning: obsolete: Do not use add_show_from_set(), instead use add_setshow...() (add_show_from_set() is very I18N unfriendly - see PR gdb/434)
m32r-tdep.c:114: warning: code: Do not use &&, or || at the end of a line
m32r-tdep.c:130: warning: code: Do not use &&, or || at the end of a line
m32r-tdep.c:159: warning: code: Do not use &&, or || at the end of a line
m32r-tdep.c:174: warning: code: Do not use &&, or || at the end of a line
m32r-tdep.c:365: warning: code: Do not use &&, or || at the end of a line
m32r-tdep.c:567: warning: code: Do not use &&, or || at the end of a line
m32r-tdep.c:620: warning: obsolete: Replace frame_unwind_unsigned_register with frame_unwind_register_unsigned
m32r-tdep.c:629: warning: obsolete: Replace frame_unwind_unsigned_register with frame_unwind_register_unsigned
m32r-tdep.c:664: warning: obsolete: Replace read_register() with regcache_read() et.al.
m32r-tdep.c:684: warning: obsolete: Replace frame_unwind_unsigned_register with frame_unwind_register_unsigned
m32r-tdep.c:747: warning: obsolete: Replace REGISTER_RAW_SIZE with register_size
m32r-tdep.c:766: warning: obsolete: Replace REGISTER_RAW_SIZE with register_size
m32r-tdep.c:773: warning: obsolete: Replace REGISTER_RAW_SIZE with register_size
m32r-tdep.c:774: warning: obsolete: Replace REGISTER_RAW_SIZE with register_size
m32r-tdep.c:815: warning: obsolete: Replace frame_unwind_unsigned_register with frame_unwind_register_unsigned
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] revised m32r target
2003-07-21 18:49 ` Andrew Cagney
@ 2003-07-22 5:00 ` Kei Sakamoto
2003-07-27 16:24 ` Andrew Cagney
0 siblings, 1 reply; 8+ messages in thread
From: Kei Sakamoto @ 2003-07-22 5:00 UTC (permalink / raw)
To: Andrew Cagney; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 608 bytes --]
> Kei,
>
> I've checked in the .c files, as posted. Not bad, not bad at all.
> Can you just see how many of the attached can also be fixed? I'll then
> look at enabling it and pulling it into the 6 branch.
>
> Andrew
Thank you for checking in. I revised m32r-tdep.c and m32r-rom.c.
I think all warnings in your e-mail are fixed now. I attached the
patch file.
By the way, would you tell me how to get these warning messages?
I built gdb with --enable-build-warnings, but gcc didn't show them.
Kei
===
2003-07-22 Kei Sakamoto <sakamoto.kei@renesas.com>
* m32r-rom.c, m32r-tdep.c: Update.
[-- Attachment #2: diffs --]
[-- Type: application/octet-stream, Size: 9356 bytes --]
diff -Naur src.orig/gdb/m32r-rom.c src/gdb/m32r-rom.c
--- src.orig/gdb/m32r-rom.c Tue Jul 22 08:07:28 2003
+++ src/gdb/m32r-rom.c Tue Jul 22 12:10:13 2003
@@ -40,8 +40,6 @@
#include <ctype.h>
#include "regcache.h"
-extern void report_transfer_performance (unsigned long, time_t, time_t);
-
/*
* All this stuff just to get my host computer's IP address!
*/
@@ -165,7 +163,8 @@
#endif
end_time = time (NULL);
printf_filtered ("Start address 0x%lx\n", bfd_get_start_address (abfd));
- report_transfer_performance (data_count, start_time, end_time);
+ print_transfer_performance (gdb_stdout, data_count, 0,
+ end_time - start_time);
/* Finally, make the PC point at the start address */
if (exec_bfd)
@@ -264,7 +263,9 @@
if (regno == SPI_REGNUM || regno == SPU_REGNUM)
{ /* special handling for stack pointer (spu or spi) */
- unsigned long stackmode = read_register (PSW_REGNUM) & 0x80;
+ ULONGEST stackmode, psw;
+ regcache_cooked_read_unsigned (current_regcache, PSW_REGNUM, &psw);
+ stackmode = psw & 0x80;
if (regno == SPI_REGNUM && !stackmode) /* SP == SPI */
monitor_supply_register (SP_REGNUM, val);
@@ -568,8 +569,9 @@
}
/* Finally, make the PC point at the start address */
write_pc (bfd_get_start_address (abfd));
- report_transfer_performance (data_count, start_time, end_time);
printf_filtered ("Start address 0x%lx\n", bfd_get_start_address (abfd));
+ print_transfer_performance (gdb_stdout, data_count, 0,
+ end_time - start_time);
}
inferior_ptid = null_ptid; /* No process now */
@@ -610,23 +612,23 @@
mon2000_ops.to_open = mon2000_open;
add_target (&mon2000_ops);
- add_show_from_set
- (add_set_cmd ("download-path", class_obscure, var_string,
- (char *) &download_path,
- "Set the default path for downloadable SREC files.",
- &setlist), &showlist);
-
- add_show_from_set
- (add_set_cmd ("board-address", class_obscure, var_string,
- (char *) &board_addr,
- "Set IP address for M32R-EVA target board.",
- &setlist), &showlist);
-
- add_show_from_set
- (add_set_cmd ("server-address", class_obscure, var_string,
- (char *) &server_addr,
- "Set IP address for download server (GDB's host computer).",
- &setlist), &showlist);
+ add_setshow_cmd ("download-path", class_obscure,
+ var_string, &download_path,
+ "Set the default path for downloadable SREC files.",
+ "Show the default path for downloadable SREC files.",
+ NULL, NULL, &setlist, &showlist);
+
+ add_setshow_cmd ("board-address", class_obscure,
+ var_string, &board_addr,
+ "Set IP address for M32R-EVA target board.",
+ "Show IP address for M32R-EVA target board.",
+ NULL, NULL, &setlist, &showlist);
+
+ add_setshow_cmd ("server-address", class_obscure,
+ var_string, &server_addr,
+ "Set IP address for download server (GDB's host computer).",
+ "Show IP address for download server (GDB's host computer).",
+ NULL, NULL, &setlist, &showlist);
add_com ("upload", class_obscure, m32r_upload_command,
"Upload the srec file via the monitor's Ethernet upload capability.");
diff -Naur src.orig/gdb/m32r-tdep.c src/gdb/m32r-tdep.c
--- src.orig/gdb/m32r-tdep.c Tue Jul 22 08:07:29 2003
+++ src/gdb/m32r-tdep.c Tue Jul 22 13:38:11 2003
@@ -111,8 +111,8 @@
/* Determine appropriate breakpoint contents and size for this address. */
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
- if (((addr & 3) == 0) &&
- ((contents_cache[0] & 0x80) || (contents_cache[2] & 0x80)))
+ if (((addr & 3) == 0)
+ && ((contents_cache[0] & 0x80) || (contents_cache[2] & 0x80)))
{
static unsigned char insn[] = M32R_BE_BREAKPOINT32;
bp = insn;
@@ -127,8 +127,8 @@
}
else
{ /* little-endian */
- if (((addr & 3) == 0) &&
- ((contents_cache[1] & 0x80) || (contents_cache[3] & 0x80)))
+ if (((addr & 3) == 0)
+ && ((contents_cache[1] & 0x80) || (contents_cache[3] & 0x80)))
{
static unsigned char insn[] = M32R_LE_BREAKPOINT32;
bp = insn;
@@ -156,8 +156,8 @@
/* Determine appropriate breakpoint contents and size for this address. */
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
- if (((addr & 3) == 0) &&
- ((contents_cache[0] & 0x80) || (contents_cache[2] & 0x80)))
+ if (((addr & 3) == 0)
+ && ((contents_cache[0] & 0x80) || (contents_cache[2] & 0x80)))
{
static unsigned char insn[] = M32R_BE_BREAKPOINT32;
bplen = sizeof (insn);
@@ -171,8 +171,8 @@
else
{
/* little-endian */
- if (((addr & 3) == 0) &&
- ((contents_cache[1] & 0x80) || (contents_cache[3] & 0x80)))
+ if (((addr & 3) == 0)
+ && ((contents_cache[1] & 0x80) || (contents_cache[3] & 0x80)))
{
static unsigned char insn[] = M32R_BE_BREAKPOINT32;
bplen = sizeof (insn);
@@ -362,9 +362,9 @@
}
else
{
- if (((insn >> 8) == 0xe4) && /* ld24 r4, xxxxxx; sub sp, r4 */
- read_memory_unsigned_integer (current_pc + 2,
- 2) == 0x0f24)
+ if (((insn >> 8) == 0xe4) /* ld24 r4, xxxxxx; sub sp, r4 */
+ && read_memory_unsigned_integer (current_pc + 2,
+ 2) == 0x0f24)
/* subtract 24 bit sign-extended negative-offset */
{
insn = read_memory_unsigned_integer (current_pc - 2, 4);
@@ -564,9 +564,9 @@
short n = op & 0xffff;
info->sp_offset += n;
}
- else if (((op >> 8) == 0xe4) && /* ld24 r4, xxxxxx; sub sp, r4 */
- get_frame_memory_unsigned (next_frame, pc + 4,
- 2) == 0x0f24)
+ else if (((op >> 8) == 0xe4) /* ld24 r4, xxxxxx; sub sp, r4 */
+ && get_frame_memory_unsigned (next_frame, pc + 4,
+ 2) == 0x0f24)
{
unsigned long n = op & 0xffffff;
info->sp_offset += n;
@@ -617,7 +617,7 @@
/* The SP was moved to the FP. This indicates that a new frame
was created. Get THIS frame's FP value by unwinding it from
the next frame. */
- frame_unwind_unsigned_register (next_frame, M32R_FP_REGNUM, &this_base);
+ this_base = frame_unwind_register_unsigned (next_frame, M32R_FP_REGNUM);
/* The FP points at the last saved register. Adjust the FP back
to before the first saved register giving the SP. */
prev_sp = this_base + info->size;
@@ -626,7 +626,7 @@
{
/* Assume that the FP is this frame's SP but with that pushed
stack space added back. */
- frame_unwind_unsigned_register (next_frame, M32R_SP_REGNUM, &this_base);
+ this_base = frame_unwind_register_unsigned (next_frame, M32R_SP_REGNUM);
prev_sp = this_base + info->size;
}
@@ -657,11 +657,11 @@
m32r_read_pc (ptid_t ptid)
{
ptid_t save_ptid;
- CORE_ADDR pc;
+ ULONGEST pc;
save_ptid = inferior_ptid;
inferior_ptid = ptid;
- pc = (int) read_register (M32R_PC_REGNUM);
+ regcache_cooked_read_unsigned (current_regcache, M32R_PC_REGNUM, &pc);
inferior_ptid = save_ptid;
return pc;
}
@@ -680,9 +680,7 @@
static CORE_ADDR
m32r_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
- ULONGEST sp;
- frame_unwind_unsigned_register (next_frame, M32R_SP_REGNUM, &sp);
- return sp;
+ return frame_unwind_register_unsigned (next_frame, M32R_SP_REGNUM);
}
@@ -744,7 +742,7 @@
else if (len < 4)
{
/* value gets right-justified in the register or stack word */
- memcpy (valbuf + (REGISTER_RAW_SIZE (argreg) - len),
+ memcpy (valbuf + (register_size (gdbarch, argreg) - len),
(char *) VALUE_CONTENTS (args[argnum]), len);
val = valbuf;
}
@@ -763,15 +761,16 @@
{
/* there's room in a register */
regval =
- extract_unsigned_integer (val, REGISTER_RAW_SIZE (argreg));
+ extract_unsigned_integer (val,
+ register_size (gdbarch, argreg));
regcache_cooked_write_unsigned (regcache, argreg++, regval);
}
/* 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);
+ len -= register_size (gdbarch, argreg);
+ val += register_size (gdbarch, argreg);
}
}
@@ -811,9 +810,7 @@
static CORE_ADDR
m32r_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
- ULONGEST pc;
- frame_unwind_unsigned_register (next_frame, M32R_PC_REGNUM, &pc);
- return pc;
+ return frame_unwind_register_unsigned (next_frame, M32R_PC_REGNUM);
}
/* Given a GDB frame, determine the address of the calling function's
@@ -884,7 +881,7 @@
};
static const struct frame_unwind *
-m32r_frame_p (CORE_ADDR pc)
+m32r_frame_sniffer (struct frame_info *next_frame)
{
return &m32r_frame_unwind;
}
@@ -966,7 +963,7 @@
set_gdbarch_frame_align (gdbarch, m32r_frame_align);
- frame_unwind_append_predicate (gdbarch, m32r_frame_p);
+ frame_unwind_append_sniffer (gdbarch, m32r_frame_sniffer);
frame_base_set_default (gdbarch, &m32r_frame_base);
/* Methods for saving / extracting a dummy frame's ID. The ID's
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH] revised m32r target
2003-07-22 5:00 ` Kei Sakamoto
@ 2003-07-27 16:24 ` Andrew Cagney
2003-07-28 6:45 ` Kei Sakamoto
0 siblings, 1 reply; 8+ messages in thread
From: Andrew Cagney @ 2003-07-27 16:24 UTC (permalink / raw)
To: Kei Sakamoto; +Cc: gdb-patches
> Kei,
>>
>> I've checked in the .c files, as posted. Not bad, not bad at all.
>> Can you just see how many of the attached can also be fixed? I'll then
>> look at enabling it and pulling it into the 6 branch.
>>
>> Andrew
>
>
> Thank you for checking in. I revised m32r-tdep.c and m32r-rom.c.
> I think all warnings in your e-mail are fixed now. I attached the
> patch file.
>
> By the way, would you tell me how to get these warning messages?
I ran the script: "gdb_ari.sh -Wari <file>". See:
http://sources.redhat.com/gdb/current/ari/
http://sources.redhat.com/gdb/current/ari/gdb_ari.sh
> I built gdb with --enable-build-warnings, but gcc didn't show them.
Can you try configuring/building with:
--enable-gdb-build-warnings=,-Werror
(all targets should configure/build with that) I'm seeing the warnings:
m32r-tdep.c: In function `m32r_store_return_value':
m32r-tdep.c:289: warning: pointer of type `void *' used in arithmetic
m32r-rom.c: In function `m32r_upload_command':
m32r-rom.c:466: warning: `hostent' might be used uninitialized in this
function
Can you please try to reproduce / fix this.
BTW, for the ChangeLog I checked in:
2003-07-27 Andrew Cagney <cagney@redhat.com>
Patch from 2003-07-22 Kei Sakamoto <sakamoto.kei@renesas.com>:
* m32r-tdep.c (m32r_memory_insert_breakpoint): Fix code style -
operator at start and not end of line.
(decode_prologue): Ditto.
(m32r_frame_unwind_cache, m32r_unwind_sp, m32r_unwind_pc): Use
frame_unwind_register_unsigned instead of
frame_unwind_unsigned_register.
(m32r_read_pc): Use regcache_cooked_read_unsigned instead of
read_register.
(m32r_push_dummy_call): Use register_size instead of
REGISTER_RAW_SIZE.
(m32r_frame_sniffer): Replace m32r_frame_p.
(m32r_gdbarch_init): Call frame_unwind_append_sniffer.
* m32r-rom.c (report_transfer_performance): Delete extern
declaration.
(m32r_load, m32r_upload_command): Use print_transfer_performance
instead of report_transfer_performance.
(_initialize_m32r_rom): Use add_setshow_cmd instead of add_set_cmd
/ add_show_from_set.
as it better states what was changed.
Andrew
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] revised m32r target
2003-07-27 16:24 ` Andrew Cagney
@ 2003-07-28 6:45 ` Kei Sakamoto
2003-08-01 21:12 ` Andrew Cagney
0 siblings, 1 reply; 8+ messages in thread
From: Kei Sakamoto @ 2003-07-28 6:45 UTC (permalink / raw)
To: Andrew Cagney; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1940 bytes --]
> Can you try configuring/building with:
>
> --enable-gdb-build-warnings=,-Werror
>
> (all targets should configure/build with that) I'm seeing the warnings:
>
> m32r-tdep.c: In function `m32r_store_return_value':
> m32r-tdep.c:289: warning: pointer of type `void *' used in arithmetic
> m32r-rom.c: In function `m32r_upload_command':
> m32r-rom.c:466: warning: `hostent' might be used uninitialized in this
> function
>
> Can you please try to reproduce / fix this.
I fixed them and attached a patch file.
2003-07-28 Kei Sakamoto <sakamoto.kei@renesas.com>
* m32r-rom.c (m32r_upload_command): Use hostent only when
gethostname succeeds, in order to avoid a compilation
warning.
* m32r-tdep.c (m32r_store_return_value): Add a cast to
remove a compiler warning.
> BTW, for the ChangeLog I checked in:
>
> 2003-07-27 Andrew Cagney <cagney@redhat.com>
>
> Patch from 2003-07-22 Kei Sakamoto <sakamoto.kei@renesas.com>:
> * m32r-tdep.c (m32r_memory_insert_breakpoint): Fix code style -
> operator at start and not end of line.
> (decode_prologue): Ditto.
> (m32r_frame_unwind_cache, m32r_unwind_sp, m32r_unwind_pc): Use
> frame_unwind_register_unsigned instead of
> frame_unwind_unsigned_register.
> (m32r_read_pc): Use regcache_cooked_read_unsigned instead of
> read_register.
> (m32r_push_dummy_call): Use register_size instead of
> REGISTER_RAW_SIZE.
> (m32r_frame_sniffer): Replace m32r_frame_p.
> (m32r_gdbarch_init): Call frame_unwind_append_sniffer.
> * m32r-rom.c (report_transfer_performance): Delete extern
> declaration.
> (m32r_load, m32r_upload_command): Use print_transfer_performance
> instead of report_transfer_performance.
> (_initialize_m32r_rom): Use add_setshow_cmd instead of add_set_cmd
> / add_show_from_set.
>
>
> as it better states what was changed.
Thank you. This is much better than mine.
===
Kei Sakamoto
Renesas Technology Corp.
sakamoto.kei@renesas.com
[-- Attachment #2: diffs --]
[-- Type: application/octet-stream, Size: 1328 bytes --]
diff -Naur src.orig/gdb/m32r-rom.c src/gdb/m32r-rom.c
--- src.orig/gdb/m32r-rom.c Mon Jul 28 00:38:16 2003
+++ src/gdb/m32r-rom.c Mon Jul 28 15:04:54 2003
@@ -492,16 +492,18 @@
buf[0] = 0;
gethostname (buf, sizeof (buf));
if (buf[0] != 0)
- hostent = gethostbyname (buf);
- if (hostent != 0)
{
+ hostent = gethostbyname (buf);
+ if (hostent != 0)
+ {
#if 1
- memcpy (&inet_addr.s_addr, hostent->h_addr,
- sizeof (inet_addr.s_addr));
- server_addr = (char *) inet_ntoa (inet_addr);
+ memcpy (&inet_addr.s_addr, hostent->h_addr,
+ sizeof (inet_addr.s_addr));
+ server_addr = (char *) inet_ntoa (inet_addr);
#else
- server_addr = (char *) inet_ntoa (hostent->h_addr);
+ server_addr = (char *) inet_ntoa (hostent->h_addr);
#endif
+ }
}
if (server_addr == 0) /* failed? */
error
diff -Naur src.orig/gdb/m32r-tdep.c src/gdb/m32r-tdep.c
--- src.orig/gdb/m32r-tdep.c Mon Jul 28 00:38:16 2003
+++ src/gdb/m32r-tdep.c Mon Jul 28 15:05:26 2003
@@ -286,7 +286,7 @@
if (len > 4)
{
- regval = extract_unsigned_integer (valbuf + 4, len - 4);
+ regval = extract_unsigned_integer ((char *) valbuf + 4, len - 4);
regcache_cooked_write_unsigned (regcache, RET1_REGNUM + 1, regval);
}
}
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH] revised m32r target
2003-07-28 6:45 ` Kei Sakamoto
@ 2003-08-01 21:12 ` Andrew Cagney
0 siblings, 0 replies; 8+ messages in thread
From: Andrew Cagney @ 2003-08-01 21:12 UTC (permalink / raw)
To: Kei Sakamoto; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 476 bytes --]
> 2003-07-28 Kei Sakamoto <sakamoto.kei@renesas.com>
>
> * m32r-rom.c (m32r_upload_command): Use hostent only when
> gethostname succeeds, in order to avoid a compilation
> warning.
> * m32r-tdep.c (m32r_store_return_value): Add a cast to
> remove a compiler warning.
>
I've checked in all the attached. Next I'll:
- commit src/configure change to gcc's master repository
- import everything to 6.0 branch.
Almost there!
Andrew
[-- Attachment #2: diffs --]
[-- Type: text/plain, Size: 4113 bytes --]
2003-08-01 Andrew Cagney <cagney@redhat.com>
* NEWS: Mention that m32r is multi-arch.
From 2003-07-28 Kei Sakamoto <sakamoto.kei@renesas.com>:
* configure.tgt: Recognize m32r-*-*.
* config/m32r/tm-m32r.h: Delete file.
* config/m32r/m32r.mt: New file.
* m32r-rom.c (m32r_upload_command): Use hostent only when
gethostname succeeds, in order to avoid a compilation
warning.
* m32r-tdep.c (m32r_store_return_value): Add a cast to remove a
compiler warning.
Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.114
diff -u -r1.114 NEWS
--- NEWS 24 Jul 2003 19:59:33 -0000 1.114
+++ NEWS 1 Aug 2003 21:10:19 -0000
@@ -46,6 +46,7 @@
* Multi-arched targets.
HP/PA HPUX11, 32bit ABI (partial) hppa*-*-hpux* except hppa*64*-*-hpux11*
+Mitsubishi M32R/D w/simulator m32r-*-elf*
* OBSOLETE configurations and files
@@ -54,7 +55,6 @@
configurations, the next release of GDB will have their sources
permanently REMOVED.
-Mitsubishi M32R/D w/simulator m32r-*-elf*
Z8000 simulator z8k-zilog-none or z8ksim
Matsushita MN10200 w/simulator mn10200-*-*
H8/500 simulator h8500-hitachi-hms or h8500hms
Index: configure.tgt
===================================================================
RCS file: /cvs/src/src/gdb/configure.tgt,v
retrieving revision 1.110
diff -u -r1.110 configure.tgt
--- configure.tgt 27 Jul 2003 15:42:20 -0000 1.110
+++ configure.tgt 1 Aug 2003 21:10:20 -0000
@@ -114,7 +114,7 @@
;;
ia64*-*-*) gdb_target=ia64 ;;
-# OBSOLETE m32r-*-elf*) gdb_target=m32r ;;
+m32r-*-*) gdb_target=m32r ;;
m68hc11*-*-*|m6811*-*-*) gdb_target=m68hc11 ;;
@@ -266,6 +266,7 @@
case "${gdb_target}" in
d10v) gdb_multi_arch=yes ;;
fbsd64) gdb_multi_arch=yes ;;
+m32r) gdb_multi_arch=yes ;;
m68hc11) gdb_multi_arch=yes ;;
mn10300) gdb_multi_arch=yes ;;
x86-64linux) gdb_multi_arch=yes ;;
Index: m32r-rom.c
===================================================================
RCS file: /cvs/src/src/gdb/m32r-rom.c,v
retrieving revision 1.12
diff -u -r1.12 m32r-rom.c
--- m32r-rom.c 27 Jul 2003 15:38:16 -0000 1.12
+++ m32r-rom.c 1 Aug 2003 21:10:20 -0000
@@ -492,16 +492,18 @@
buf[0] = 0;
gethostname (buf, sizeof (buf));
if (buf[0] != 0)
- hostent = gethostbyname (buf);
- if (hostent != 0)
{
+ hostent = gethostbyname (buf);
+ if (hostent != 0)
+ {
#if 1
- memcpy (&inet_addr.s_addr, hostent->h_addr,
- sizeof (inet_addr.s_addr));
- server_addr = (char *) inet_ntoa (inet_addr);
+ memcpy (&inet_addr.s_addr, hostent->h_addr,
+ sizeof (inet_addr.s_addr));
+ server_addr = (char *) inet_ntoa (inet_addr);
#else
- server_addr = (char *) inet_ntoa (hostent->h_addr);
+ server_addr = (char *) inet_ntoa (hostent->h_addr);
#endif
+ }
}
if (server_addr == 0) /* failed? */
error
Index: m32r-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/m32r-tdep.c,v
retrieving revision 1.16
diff -u -r1.16 m32r-tdep.c
--- m32r-tdep.c 27 Jul 2003 15:38:16 -0000 1.16
+++ m32r-tdep.c 1 Aug 2003 21:10:21 -0000
@@ -286,7 +286,7 @@
if (len > 4)
{
- regval = extract_unsigned_integer (valbuf + 4, len - 4);
+ regval = extract_unsigned_integer ((char *) valbuf + 4, len - 4);
regcache_cooked_write_unsigned (regcache, RET1_REGNUM + 1, regval);
}
}
Index: config/m32r/m32r.mt
===================================================================
RCS file: /cvs/src/src/gdb/config/m32r/m32r.mt,v
retrieving revision 1.5
diff -u -r1.5 m32r.mt
--- config/m32r/m32r.mt 4 Feb 2003 23:26:43 -0000 1.5
+++ config/m32r/m32r.mt 1 Aug 2003 21:10:22 -0000
@@ -1,5 +1,4 @@
-# OBSOLETE # Target: Mitsubishi m32r processor
-# OBSOLETE TDEPFILES= m32r-tdep.o monitor.o m32r-rom.o dsrec.o
-# OBSOLETE TM_FILE= tm-m32r.h
-# OBSOLETE SIM_OBS = remote-sim.o
-# OBSOLETE SIM = ../sim/m32r/libsim.a
+# Target: Renesas m32r processor
+TDEPFILES= m32r-tdep.o monitor.o m32r-rom.o dsrec.o
+SIM_OBS = remote-sim.o
+SIM = ../sim/m32r/libsim.a
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2003-08-01 21:12 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-07-04 2:00 [PATCH] revised m32r target Kei Sakamoto
2003-07-11 7:15 ` Kei Sakamoto
2003-07-11 13:31 ` Andrew Cagney
2003-07-21 18:49 ` Andrew Cagney
2003-07-22 5:00 ` Kei Sakamoto
2003-07-27 16:24 ` Andrew Cagney
2003-07-28 6:45 ` Kei Sakamoto
2003-08-01 21:12 ` Andrew Cagney
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox