From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 32640 invoked by alias); 24 Aug 2005 01:16:15 -0000 Mailing-List: contact rda-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Post: List-Help: , Sender: rda-owner@sources.redhat.com Received: (qmail 32604 invoked by uid 22791); 24 Aug 2005 01:16:01 -0000 Received: from mx1.redhat.com (HELO mx1.redhat.com) (66.187.233.31) by sourceware.org (qpsmtpd/0.30-dev) with ESMTP; Wed, 24 Aug 2005 01:16:01 +0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.12.11/8.12.11) with ESMTP id j7O1G0tD014490 for ; Tue, 23 Aug 2005 21:16:00 -0400 Received: from pobox.corp.redhat.com (pobox.corp.redhat.com [172.16.52.156]) by int-mx1.corp.redhat.com (8.11.6/8.11.6) with ESMTP id j7O1G0V10334 for ; Tue, 23 Aug 2005 21:16:00 -0400 Received: from localhost.localdomain (vpn50-47.rdu.redhat.com [172.16.50.47]) by pobox.corp.redhat.com (8.12.8/8.12.8) with ESMTP id j7O1FwZa031197 for ; Tue, 23 Aug 2005 21:15:59 -0400 Received: from ironwood.lan (ironwood.lan [192.168.64.8]) by localhost.localdomain (8.12.11/8.12.10) with ESMTP id j7O1FrEY001413 for ; Tue, 23 Aug 2005 18:15:53 -0700 Date: Wed, 24 Aug 2005 01:16:00 -0000 From: Kevin Buettner To: rda@sources.redhat.com Subject: [PATCH] Add support for am33 linux Message-ID: <20050823181553.65e03d9c@ironwood.lan> Organization: Red Hat X-Mailer: Sylpheed-Claws 0.9.12cvs173.1 (GTK+ 2.4.14; i386-redhat-linux-gnu) Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit X-SW-Source: 2005-q3/txt/msg00002.txt.bz2 I've just committed the patch below. * configure.in (am33_2.0*linux*): New target. * Makefile.in: Regenerate. * aclocal.m4: Regenerate. * config.in: Regenerate. * configure: Regenerate. * gdbserv-thread-db.h (mips_singlestep): Change return type to ``void''. (am33_singlestep): New declaration. * linux-target.c [AM33_2_0_LINUX_TARGET] (GETREGS_SETREGS_REGINFO, SOFTWARE_SINGLESTEP, PC_REGNUM, A0_REGNUM) (A1_REGNUM, A2_REGNUM, A3_REGNUM, LAR_REGNUM, MDR_REGNUM, SP_REGNUM) (NUM_REGS, sign_extend): Define. (PT_A3, PT_A2, PT_D3, PT_D2, PT_MCVF, PT_MCRL, PT_MCRH, PT_MDRQ) (PT_E1, PT_E0, PT_E7, PT_E6, PT_E5, PT_E4, PT_E3, PT_E2, PT_SP) (PT_LAR, PT_LIR, PT_MDR, PT_A1, PT_A0, PT_D1, PT_D0, PT_ORIG_D0) (PT_EPSW, PT_PC): Define. (reginfo): New table. (stock_table_to_am33, am33_table_to_stock, stock_bp_to_am33) (am33_bp_to_stock, am33_make_bp_table, am33_set_bp, am33_delete_bp) (am33_bp_hit_p, am33_make_arch): New functions. (MAKE_ARCH): Define. (am33_singlestep_program, am33_read_byte, am33_read_disp16) (am33_read_disp32, am33_get_register, am33_get_areg, am33_singlestep): New functions. (am33_opcode_size): New table. [MIPS_LINUX_TARGET | MIPS64_LINUX_TARGET] (SOFTWARE_SINGLESTEP): Define. (linux_attach): Set am33 specific ``singlestep_program''. Revise proprocessor condition upon which ``is_ss'' is set. [SOFTWARE_SINGLESTEP] (set_singlestep_breakpoint): New function. (mips_get_reg, mips_poke_instruction): Delete. (mips_singlestep): Adjust return type. Use set_singlestep_breakpoint() where appropriate. * ptrace-target.c (handle_waitstatus): Adjust call to ptrace_set_mem() to account for different type of singlestep breakpoint shadow value. Also, pass the stored breakpoint size. Add diagnostics. (ptrace_attach): Add AM33_2_0_LINUX_TARGET to list of targets needing to clear ``is_ss''. (singlestep_lwp): Add code to call am33 specific singlestep code. * server.h (struct ss_save): Add AM33_2_0_LINUX_TARGET to the list of preprocessor conditions which declare this struct. Revise type of ``ss_val'' from ``int'' to a ``char'' array. Add new field ``ss_size''. (struct child_process): Define fields ``is_ss'' and ``ss_info'' for AM33_2_0_LINUX_TARGET. Index: configure.in =================================================================== RCS file: /cvs/src/src/rda/unix/configure.in,v retrieving revision 1.8 diff -u -p -r1.8 configure.in --- configure.in 30 Jun 2005 03:24:18 -0000 1.8 +++ configure.in 24 Aug 2005 01:12:08 -0000 @@ -64,6 +64,16 @@ AH_TEMPLATE(PTRACE_XFER_TYPE_LONG_LONG, [Define if ptrace transfer type is long long or unsigned long long.]) case "$target" in + am33_2.0*linux*) + TARGET_MODULES="linux-target.o thread-db.o lwp-pool.o ptrace-target.o" + AC_DEFINE(LINUX_TARGET) + AC_DEFINE(GREGSET_T, prgregset_t) + AC_DEFINE(HAVE_LWPID_T) + AC_DEFINE(HAVE_PSADDR_T) + AC_DEFINE(HAVE_PRGREGSET_T) + AC_DEFINE(FPREGSET_T, prfpregset_t) + AC_DEFINE(HAVE_PRFPREGSET_T) + ;; mips64*linux*) TARGET_MODULES="linux-target.o thread-db.o lwp-pool.o ptrace-target.o" AC_DEFINE(LINUX_TARGET) @@ -110,7 +120,7 @@ esac # Some architectures use the stock breakpoint model. case "$target" in - i?86*linux* | frv*linux*) + i?86*linux* | frv*linux* | am33*linux*) TARGET_MODULES="$TARGET_MODULES stock-breakpoints.o" AC_DEFINE(STOCK_BREAKPOINTS, [1], [Define if the target uses the stock-breakpoints.o module.]) @@ -120,6 +130,16 @@ esac AC_SUBST(TARGET_MODULES) case "$target" in + am33_2.0*linux*) + AC_DEFINE(AM33_2_0_LINUX_TARGET, [1], + [Define if target is am33 Linux.]) + AC_DEFINE(PTRACE_XFER_SIZE, 4) + AC_DEFINE(PTRACE_XFER_TYPE_LONG) + AC_DEFINE(PTRACE_ARG1_TYPE_LONG) + AC_DEFINE(PTRACE_ARG2_TYPE_LONG) + AC_DEFINE(PTRACE_ARG3_TYPE_LONG) + AC_DEFINE(PTRACE_ARG4_TYPE_LONG) + ;; *solaris*) dnl FIXME: differentiate between flavors of Solaris! AC_DEFINE(SPARC32_SOLARIS_TARGET, [1], Index: gdbserv-thread-db.h =================================================================== RCS file: /cvs/src/src/rda/unix/gdbserv-thread-db.h,v retrieving revision 1.5 diff -u -p -r1.5 gdbserv-thread-db.h --- gdbserv-thread-db.h 23 Aug 2005 23:22:17 -0000 1.5 +++ gdbserv-thread-db.h 24 Aug 2005 01:12:08 -0000 @@ -86,8 +86,12 @@ extern int reg_from_xregset (struct gdbs /* Software singlestep for mips. */ #if defined (MIPS_LINUX_TARGET) || defined (MIPS64_LINUX_TARGET) -extern int mips_singlestep (struct gdbserv *serv, pid_t pid, int sig); +extern void mips_singlestep (struct gdbserv *serv, pid_t pid, int sig); #endif +#if defined (AM33_2_0_LINUX_TARGET) +extern void am33_singlestep (struct gdbserv *serv, pid_t pid, int sig); +#endif + /* Fetch the value of PC for debugging purposes. */ extern unsigned long debug_get_pc (struct gdbserv *serv, pid_t pid); Index: linux-target.c =================================================================== RCS file: /cvs/src/src/rda/unix/linux-target.c,v retrieving revision 1.18 diff -u -p -r1.18 linux-target.c --- linux-target.c 23 Aug 2005 23:22:17 -0000 1.18 +++ linux-target.c 24 Aug 2005 01:12:08 -0000 @@ -482,6 +482,242 @@ x86_make_arch (void) /* End of X86_LINUX_TARGET */ +#elif defined (AM33_2_0_LINUX_TARGET) || defined (AM33_LINUX_TARGET) + +/* AM33 needs to use PTRACE_GETREGS / PTRACE_SETREGS, PTRACE_GETFPREGS / + PTRACE_SETFPREGS in order to access all of the registers. */ +#define GETREGS_SETREGS_REGINFO 1 +#define SOFTWARE_SINGLESTEP 1 + +enum +{ + PC_REGNUM = 9, + A0_REGNUM = 4, + A1_REGNUM = 5, + A2_REGNUM = 6, + A3_REGNUM = 7, + LAR_REGNUM = 13, + MDR_REGNUM = 10, + SP_REGNUM = 8, + NUM_REGS = 64, + sign_extend=0 +}; + +/* These should match the constants defined in */ +#define PT_A3 0 +#define PT_A2 1 +#define PT_D3 2 +#define PT_D2 3 +#define PT_MCVF 4 +#define PT_MCRL 5 +#define PT_MCRH 6 +#define PT_MDRQ 7 +#define PT_E1 8 +#define PT_E0 9 +#define PT_E7 10 +#define PT_E6 11 +#define PT_E5 12 +#define PT_E4 13 +#define PT_E3 14 +#define PT_E2 15 +#define PT_SP 16 +#define PT_LAR 17 +#define PT_LIR 18 +#define PT_MDR 19 +#define PT_A1 20 +#define PT_A0 21 +#define PT_D1 22 +#define PT_D0 23 +#define PT_ORIG_D0 24 +#define PT_EPSW 25 +#define PT_PC 26 + +static struct getregs_setregs_reginfo reginfo[] = +{ + { GREGS, PT_D0 * 4, sizeof (greg_t), 4 }, + { GREGS, PT_D1 * 4, sizeof (greg_t), 4 }, + { GREGS, PT_D2 * 4, sizeof (greg_t), 4 }, + { GREGS, PT_D3 * 4, sizeof (greg_t), 4 }, + { GREGS, PT_A0 * 4, sizeof (greg_t), 4 }, + { GREGS, PT_A1 * 4, sizeof (greg_t), 4 }, + { GREGS, PT_A2 * 4, sizeof (greg_t), 4 }, + { GREGS, PT_A3 * 4, sizeof (greg_t), 4 }, + { GREGS, PT_SP * 4, sizeof (greg_t), 4 }, + { GREGS, PT_PC * 4, sizeof (greg_t), 4 }, + { GREGS, PT_MDR * 4, sizeof (greg_t), 4 }, + { GREGS, PT_EPSW * 4, sizeof (greg_t), 4 }, /* psw */ + { GREGS, PT_LIR * 4, sizeof (greg_t), 4 }, + { GREGS, PT_LAR * 4, sizeof (greg_t), 4 }, + { GREGS, PT_MDRQ * 4, sizeof (greg_t), 4 }, + { GREGS, PT_E0 * 4, sizeof (greg_t), 4 }, /* r0 */ + { GREGS, PT_E1 * 4, sizeof (greg_t), 4 }, /* r1 */ + { GREGS, PT_E2 * 4, sizeof (greg_t), 4 }, /* r2 */ + { GREGS, PT_E3 * 4, sizeof (greg_t), 4 }, /* r3 */ + { GREGS, PT_E4 * 4, sizeof (greg_t), 4 }, /* r4 */ + { GREGS, PT_E5 * 4, sizeof (greg_t), 4 }, /* r5 */ + { GREGS, PT_E6 * 4, sizeof (greg_t), 4 }, /* r6 */ + { GREGS, PT_E7 * 4, sizeof (greg_t), 4 }, /* r7 */ + { GREGS, PT_SP * 4, sizeof (greg_t), 4 }, /* ssp */ + { GREGS, PT_SP * 4, sizeof (greg_t), 4 }, /* msp */ + { GREGS, PT_SP * 4, sizeof (greg_t), 4 }, /* usp */ + { GREGS, PT_MCRH * 4, sizeof (greg_t), 4 }, + { GREGS, PT_MCRL * 4, sizeof (greg_t), 4 }, + { GREGS, PT_MCVF * 4, sizeof (greg_t), 4 }, + + /* AM33 uses single precision floating point registers where two + consecutive registers are combined to form a double. The + register layout is defined (in the kernel sources) in + include/asm-mn10300/processor.h. Unfortunately, this file is not + easily included, so we'll use hard coded constants for the + offsets and sizes... */ + + { FPREGS, 32 * 4, 4, 4 }, /* fpcr */ + + /* The "g" packet has a gap between fpcr and fs0. */ + { NOREGS, 0, 0, 4 }, + { NOREGS, 0, 0, 4 }, + + { FPREGS, 0 * 4, 4, 4 }, /* fs0 */ + { FPREGS, 1 * 4, 4, 4 }, /* fs1 ... */ + { FPREGS, 2 * 4, 4, 4 }, + { FPREGS, 3 * 4, 4, 4 }, + { FPREGS, 4 * 4, 4, 4 }, + { FPREGS, 5 * 4, 4, 4 }, + { FPREGS, 6 * 4, 4, 4 }, + { FPREGS, 7 * 4, 4, 4 }, + { FPREGS, 8 * 4, 4, 4 }, + { FPREGS, 9 * 4, 4, 4 }, + { FPREGS, 10 * 4, 4, 4 }, + { FPREGS, 11 * 4, 4, 4 }, + { FPREGS, 12 * 4, 4, 4 }, + { FPREGS, 13 * 4, 4, 4 }, + { FPREGS, 14 * 4, 4, 4 }, + { FPREGS, 15 * 4, 4, 4 }, + { FPREGS, 16 * 4, 4, 4 }, + { FPREGS, 17 * 4, 4, 4 }, + { FPREGS, 18 * 4, 4, 4 }, + { FPREGS, 19 * 4, 4, 4 }, + { FPREGS, 20 * 4, 4, 4 }, + { FPREGS, 21 * 4, 4, 4 }, + { FPREGS, 22 * 4, 4, 4 }, + { FPREGS, 23 * 4, 4, 4 }, + { FPREGS, 24 * 4, 4, 4 }, + { FPREGS, 25 * 4, 4, 4 }, + { FPREGS, 26 * 4, 4, 4 }, + { FPREGS, 27 * 4, 4, 4 }, + { FPREGS, 28 * 4, 4, 4 }, + { FPREGS, 29 * 4, 4, 4 }, + { FPREGS, 30 * 4, 4, 4 }, + { FPREGS, 31 * 4, 4, 4 } /* fs31 */ +}; + +static void am33_singlestep_program (struct gdbserv *serv); + +/* Breakpoint methods for the am33. Except for bp_hit_p, these + are just wrappers for the stock breakpoint methods. In C++, we + could use multiple inheritance for this, and it would all just + work... */ + +/* am33 breakpoints tables are just stock breakpoint tables. But we + like static typechecking; casts swallow error messages. */ +static struct arch_bp_table * +stock_table_to_am33 (struct stock_bp_table *table) +{ + return (struct arch_bp_table *) table; +} + +static struct stock_bp_table * +am33_table_to_stock (struct arch_bp_table *table) +{ + return (struct stock_bp_table *) table; +} + +/* am33 breakpoints are just stock breakpoints. But we like static + typechecking; casts swallow error messages. */ +static struct arch_bp * +stock_bp_to_am33 (struct stock_bp *bp) +{ + return (struct arch_bp *) bp; +} + +static struct stock_bp * +am33_bp_to_stock (struct arch_bp *bp) +{ + return (struct stock_bp *) bp; +} + +struct arch_bp_table * +am33_make_bp_table (struct arch *arch, + struct gdbserv *serv, + struct gdbserv_target *target) +{ + struct stock_bp_table *table = stock_bp_make_table (serv, target); + + /* Use 0xff as the breakpoint instruction. */ + stock_bp_set_bp_insn (table, 1, "\xff"); + + return stock_table_to_am33 (table); +} + + +static struct arch_bp * +am33_set_bp (struct arch_bp_table *table, + struct gdbserv_reg *addr) +{ + /* am33 arch breakpoints are just stock breakpoints. */ + return stock_bp_to_am33 (stock_bp_set_bp (am33_table_to_stock (table), + addr)); +} + + +static int +am33_delete_bp (struct arch_bp *bp) +{ + return stock_bp_delete_bp (am33_bp_to_stock (bp)); +} + + +static int +am33_bp_hit_p (struct gdbserv_thread *thread, + struct arch_bp *arch_bp) +{ + struct stock_bp *bp = am33_bp_to_stock (arch_bp); + struct stock_bp_table *table = stock_bp_table (bp); + struct gdbserv *serv = stock_bp_table_serv (table); + struct gdbserv_target *target = stock_bp_table_target (table); + struct gdbserv_reg bp_addr, pc; + unsigned long bp_addr_int, pc_int; + + stock_bp_addr (&bp_addr, bp); + gdbserv_reg_to_ulong (serv, &bp_addr, &bp_addr_int); + target->get_thread_reg (serv, thread, PC_REGNUM, &pc); + gdbserv_reg_to_ulong (serv, &pc, &pc_int); + + /* When the am33 hits a breakpoint, the reported PC value is equal to + address of the breakpoint. */ + return bp_addr_int == pc_int; +} + + +/* Construct an architecture object for the am33. */ +static struct arch * +am33_make_arch (void) +{ + struct arch *a = allocate_empty_arch (); + + a->closure = 0; /* No closure needed at the moment. */ + a->make_bp_table = am33_make_bp_table; + a->set_bp = am33_set_bp; + a->delete_bp = am33_delete_bp; + a->bp_hit_p = am33_bp_hit_p; + + return a; +} + +#define MAKE_ARCH() (am33_make_arch ()) + +/* End of AM33_LINUX_TARGET */ + #elif defined (SH_LINUX_TARGET) /* Needs to be converted to use either GETREGS_SETREGS_REGINFO or @@ -529,6 +765,7 @@ is_extended_reg (int regnum) #elif defined MIPS_LINUX_TARGET || (defined MIPS64_LINUX_TARGET && defined MIPS_ABI_O32) #define PEEKUSER_POKEUSER_REGINFO 1 +#define SOFTWARE_SINGLESTEP 1 enum { @@ -682,6 +919,7 @@ static void mips_singlestep_program (str #elif defined(MIPS64_LINUX_TARGET) #define PEEKUSER_POKEUSER_REGINFO 1 +#define SOFTWARE_SINGLESTEP 1 enum { @@ -2969,6 +3207,8 @@ linux_attach (struct gdbserv *serv, void linux_target->restart_program = NULL; #if defined(_MIPSEL) || defined(_MIPSEB) linux_target->singlestep_program = mips_singlestep_program; +#elif defined(AM33_2_0_LINUX_TARGET) + linux_target->singlestep_program = am33_singlestep_program; #else linux_target->singlestep_program = ptrace_target->singlestep_program; #endif @@ -2996,7 +3236,7 @@ linux_attach (struct gdbserv *serv, void else process->breakpoint_table = 0; -#if defined(_MIPSEL) || defined(_MIPSEB) +#if defined(SOFTWARE_SINGLESTEP) process->is_ss = 0; #endif @@ -3091,23 +3331,57 @@ decr_pc_after_break (struct gdbserv *ser } #endif +#ifdef SOFTWARE_SINGLESTEP -#if defined(_MIPSEL) || defined(_MIPSEB) - -/* - * Worker function to get and return a register - */ +/* Set a software-singlestep breakpoint. */ -static ptrace_xfer_type -mips_get_reg(struct gdbserv *serv, int pid, int regno) +static void +set_singlestep_breakpoint (struct gdbserv *serv, ptrace_arg3_type addr, + char *breakpoint_bytes, int breakpoint_length) { - ptrace_xfer_type value; + int i = 0; + struct child_process *process = gdbserv_target_data (serv); - if (read_reg_bytes (serv, pid, regno, &value) < 0) - return 0; - else - return value; + if (process->ss_info[i].in_use) + i++; + + assert (!process->ss_info[i].in_use); + + /* set flag so handle_waitstatus can restore breakpoint stuff */ + process->is_ss = 1; + + /* Mark the breakpoint used. */ + process->ss_info[i].in_use = 1; + + /* Convert ``addr'' to a struct gdbserv_reg. */ + gdbserv_host_bytes_to_reg (serv, + &addr, + sizeof (addr), + &process->ss_info[i].ss_addr, + sizeof (ptrace_arg3_type), + sign_extend); + + /* Set the breakpoint size. */ + process->ss_info[i].ss_size = breakpoint_length; + + /* Fetch the contents of the memory at which the breakpoint will be + placed. */ + ptrace_get_mem (serv, + &process->ss_info[i].ss_addr, + process->ss_info[i].ss_val, + process->ss_info[i].ss_size); + + /* Finally, set the breakpoint! */ + ptrace_set_mem (serv, + &process->ss_info[i].ss_addr, + breakpoint_bytes, + process->ss_info[i].ss_size); + if (process->debug_backend) + fprintf (stderr, "Singlestep breakpoint %d set at location %lx\n", i, addr); } +#endif /* SOFTWARE_SINGLESTEP */ + +#if defined(_MIPSEL) || defined(_MIPSEB) static struct gdbserv_reg mips_addr_as_reg (struct gdbserv *serv, ptrace_arg3_type addr) @@ -3134,21 +3408,13 @@ mips_peek_instruction (struct gdbserv *s return insn; } -static void -mips_poke_instruction (struct gdbserv *serv, ptrace_arg3_type addr, - unsigned int insn) -{ - struct gdbserv_reg addr_as_reg; - - addr_as_reg = mips_addr_as_reg (serv, addr); - ptrace_set_mem (serv, &addr_as_reg, &insn, sizeof (insn)); -} - /* * mips singlestep * * necessary since no support in ptrace. */ +void mips_singlestep (struct gdbserv *serv, pid_t pid, int sig); + static void mips_singlestep_program (struct gdbserv *serv) { @@ -3160,12 +3426,11 @@ mips_singlestep_program (struct gdbserv process->signal_to_send = 0; } -int +void mips_singlestep (struct gdbserv *serv, pid_t pid, int sig) { struct child_process *process = gdbserv_target_data (serv); - ptrace_arg3_type targ; - ptrace_xfer_type mips_pc; + ptrace_xfer_type targ, mips_pc; union mips_instruction insn; int is_branch, is_cond, i; @@ -3181,7 +3446,7 @@ mips_singlestep (struct gdbserv *serv, p /* Following is equiv to ptrace (PTRACE_SINGLESTEP, pid, 1L, sig); */ /* get the current PC */ - mips_pc = mips_get_reg(serv, pid, PC_REGNUM); + mips_pc = debug_get_reg(serv, pid, PC_REGNUM); targ = mips_pc; /* get the word there (opcode) */ @@ -3190,9 +3455,6 @@ mips_singlestep (struct gdbserv *serv, p is_branch = is_cond = 0; - /* set flag so handle_waitstatus can restore breakpoint stuff */ - process->is_ss = 1; - switch (insn.i_format.opcode) { /* * jr and jalr are in r_format format. @@ -3201,7 +3463,7 @@ mips_singlestep (struct gdbserv *serv, p switch (insn.r_format.func) { case jalr_op: case jr_op: - targ = mips_get_reg(serv, pid, insn.r_format.rs); + targ = debug_get_reg(serv, pid, insn.r_format.rs); is_branch = 1; break; } @@ -3271,30 +3533,368 @@ mips_singlestep (struct gdbserv *serv, p i = 0; if (is_cond && targ != (mips_pc + 8)) { - process->ss_info[i].in_use = 1; - process->ss_info[i].ss_addr = mips_addr_as_reg (serv, mips_pc + 8); - process->ss_info[i++].ss_val - = mips_peek_instruction (serv, mips_pc + 8); - mips_poke_instruction (serv, mips_pc + 8, bp_inst); + set_singlestep_breakpoint (serv, mips_pc + 8, &bp_inst, + sizeof (bp_inst)); } - process->ss_info[i].in_use = 1; - process->ss_info[i].ss_addr = mips_addr_as_reg (serv, targ); - process->ss_info[i].ss_val = mips_peek_instruction (serv, targ); - mips_poke_instruction (serv, targ, bp_inst); + set_singlestep_breakpoint (serv, targ, &bp_inst, + sizeof (bp_inst)); } else { - process->ss_info[0].in_use = 1; - process->ss_info[0].ss_addr = mips_addr_as_reg (serv, mips_pc + 4); - process->ss_info[0].ss_val = mips_peek_instruction (serv, mips_pc + 4); - mips_poke_instruction (serv, mips_pc + 4, bp_inst); + set_singlestep_breakpoint (serv, mips_pc + 4, &bp_inst, + sizeof (bp_inst)); } ptrace (PTRACE_CONT, pid, 1L, sig); - return 0; } #endif /* _MIPSEL */ +#if defined (AM33_2_0_LINUX_TARGET) +/* AM33 single-step support. Lifted from Redboot which was in turn + lifted from Cygmon. */ + +void am33_singlestep (struct gdbserv *serv, pid_t pid, int sig); + +static void +am33_singlestep_program (struct gdbserv *serv) +{ + struct child_process *process = gdbserv_target_data (serv); + + am33_singlestep (serv, process->pid, process->signal_to_send); + process->stop_signal = 0; + process->stop_status = 0; + process->signal_to_send = 0; +} + +/* Read a 16-bit displacement from address 'addr'. */ +static unsigned char +am33_read_byte(struct gdbserv *serv, ptrace_arg3_type addr) +{ + unsigned char val; + struct gdbserv_reg addr_as_reg; + + gdbserv_host_bytes_to_reg (serv, &addr, sizeof (addr), + &addr_as_reg, sizeof (ptrace_arg3_type), + sign_extend); + ptrace_get_mem (serv, &addr_as_reg, &val, sizeof (val)); + + return val; +} + +static short +am33_read_disp16(struct gdbserv *serv, ptrace_arg3_type addr) +{ + short val; + struct gdbserv_reg addr_as_reg; + + gdbserv_host_bytes_to_reg (serv, &addr, sizeof (addr), + &addr_as_reg, sizeof (ptrace_arg3_type), + sign_extend); + ptrace_get_mem (serv, &addr_as_reg, &val, sizeof (val)); + + return val; +} + +/* Read a 32-bit displacement from address 'p'. The + value is stored little-endian. */ + +static long +am33_read_disp32(struct gdbserv *serv, ptrace_arg3_type addr) +{ + long val; + struct gdbserv_reg addr_as_reg; + + gdbserv_host_bytes_to_reg (serv, &addr, sizeof (addr), + &addr_as_reg, sizeof (ptrace_arg3_type), + sign_extend); + ptrace_get_mem (serv, &addr_as_reg, &val, sizeof (val)); + + return val; +} + +static ptrace_arg3_type +am33_get_register (struct gdbserv *serv, pid_t pid, int regno) +{ + return debug_get_reg (serv, pid, regno); +} + + +/* Get the contents of An register. */ + +static unsigned int +am33_get_areg (struct gdbserv *serv, pid_t pid, int n) +{ + switch (n) + { + case 0: + return am33_get_register (serv, pid, A0_REGNUM); + case 1: + return am33_get_register (serv, pid, A1_REGNUM); + case 2: + return am33_get_register (serv, pid, A2_REGNUM); + case 3: + return am33_get_register (serv, pid, A3_REGNUM); + } + return 0; +} + + +/* Table of instruction sizes, indexed by first byte of instruction, + used to determine the address of the next instruction for single stepping. + If an entry is zero, special code must handle the case (for example, + branches or multi-byte opcodes). */ + +static char am33_opcode_size[256] = +{ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /*------------------------------------------------*/ +/* 0 */ 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, +/* 1 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* 2 */ 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, +/* 3 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, +/* 4 */ 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, +/* 5 */ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, +/* 6 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* 7 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* 8 */ 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, +/* 9 */ 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, +/* a */ 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, +/* b */ 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, +/* c */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2, +/* d */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* e */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* f */ 0, 2, 2, 2, 2, 2, 2, 1, 0, 3, 0, 4, 0, 6, 7, 1 +}; + +/* Set breakpoint(s) to simulate a single step from the current PC. */ + +void +am33_singlestep (struct gdbserv *serv, pid_t pid, int sig) +{ + struct child_process *process = gdbserv_target_data (serv); + ptrace_arg3_type pc; + unsigned int opcode; + int displ; + static char bp_inst = 0xff; + static int hw_singlestep_okay = 1; + + if (hw_singlestep_okay) + { + if (process->debug_backend) + fprintf (stderr, "PTRACE_SINGLESTEP (am33): pid=%d signal=%d\n", + pid, sig); + errno = 0; + ptrace (PTRACE_SINGLESTEP, pid, 1L, sig); + if (errno == 0) + return; + /* EINVAL is the expected error when the kernel doesn't support + PTRACE_SINGLESTEP. Report all other errors. */ + if (errno != EINVAL) + fprintf (stderr, "PTRACE_SINGLESTEP (am33) error: %s in %d\n", + strerror (errno), pid); + else + { + if (process->debug_backend) + fprintf (stderr, + "Disabling use of PTRACE_SINGLESTEP: It's not supported by this kernel.\n"); + hw_singlestep_okay = 0; + } + /* Fall through into software singlestep code. */ + } + + pc = am33_get_register (serv, pid, PC_REGNUM); + opcode = am33_read_byte (serv, pc); + + /* Check the table for the simple cases. */ + displ = am33_opcode_size[opcode]; + if (displ != 0) + { + set_singlestep_breakpoint (serv, pc + displ, &bp_inst, sizeof (bp_inst)); + } + else + + /* Handle the more complicated cases. */ + switch (opcode) + { + case 0xc0: + case 0xc1: + case 0xc2: + case 0xc3: + case 0xc4: + case 0xc5: + case 0xc6: + case 0xc7: + case 0xc8: + case 0xc9: + case 0xca: + /* + * bxx (d8,PC) + */ + displ = (signed char) am33_read_byte (serv, pc + 1); + set_singlestep_breakpoint (serv, pc + 2, &bp_inst, sizeof (bp_inst)); + if (displ < 0 || displ > 2) + set_singlestep_breakpoint (serv, pc + displ, &bp_inst, sizeof (bp_inst)); + break; + + case 0xd0: + case 0xd1: + case 0xd2: + case 0xd3: + case 0xd4: + case 0xd5: + case 0xd6: + case 0xd7: + case 0xd8: + case 0xd9: + case 0xda: + /* + * lxx (d8,PC) + */ + if (pc != am33_get_register (serv, pid, LAR_REGNUM)) + set_singlestep_breakpoint (serv, + am33_get_register (serv, pid, LAR_REGNUM), + &bp_inst, sizeof (bp_inst)); + set_singlestep_breakpoint (serv, pc + 1, &bp_inst, sizeof (bp_inst)); + break; + + case 0xdb: + /* + * setlb requires special attention. It loads the next four instruction + * bytes into the LIR register, so we can't insert a breakpoint in any + * of those locations. + */ + set_singlestep_breakpoint (serv, pc + 5, &bp_inst, sizeof (bp_inst)); + break; + + case 0xcc: + case 0xcd: + /* + * jmp (d16,PC) or call (d16,PC) + */ + displ = am33_read_disp16(serv, pc + 1); + set_singlestep_breakpoint (serv, pc + displ, &bp_inst, sizeof (bp_inst)); + break; + + case 0xdc: + case 0xdd: + /* + * jmp (d32,PC) or call (d32,PC) + */ + displ = am33_read_disp32(serv, pc + 1); + set_singlestep_breakpoint (serv, pc + displ, &bp_inst, sizeof (bp_inst)); + break; + + case 0xde: + /* + * retf + */ + set_singlestep_breakpoint (serv, am33_get_register (serv, pid, MDR_REGNUM), + &bp_inst, sizeof (bp_inst)); + break; + + case 0xdf: + /* + * ret + */ + displ = (signed char) am33_read_byte (serv, pc + 2); + set_singlestep_breakpoint ( + serv, + am33_read_disp32 (serv, + am33_get_register (serv, pid, SP_REGNUM) + displ), + &bp_inst, sizeof (bp_inst)); + break; + + case 0xf0: + /* + * Some branching 2-byte instructions. + */ + opcode = am33_read_byte (serv, pc + 1); + if (opcode >= 0xf0 && opcode <= 0xf7) + { + /* jmp (An) / calls (An) */ + set_singlestep_breakpoint (serv, + am33_get_areg (serv, pid, opcode & 3), + &bp_inst, sizeof (bp_inst)); + + } + else if (opcode == 0xfc) + { + /* rets */ + set_singlestep_breakpoint ( + serv, + am33_read_disp32 (serv, am33_get_register (serv, pid, SP_REGNUM)), + &bp_inst, sizeof (bp_inst)); + + } + else if (opcode == 0xfd) + { + /* rti */ + set_singlestep_breakpoint ( + serv, + am33_read_disp32 (serv, + am33_get_register (serv, pid, SP_REGNUM) + 4), + &bp_inst, sizeof (bp_inst)); + + } + else + set_singlestep_breakpoint (serv, pc + 2, &bp_inst, sizeof (bp_inst)); + + break; + + case 0xf8: + /* + * Some branching 3-byte instructions. + */ + opcode = am33_read_byte (serv, pc + 1); + if (opcode >= 0xe8 && opcode <= 0xeb) + { + displ = (signed char) am33_read_byte (serv, pc + 2); + set_singlestep_breakpoint (serv, pc + 3, &bp_inst, sizeof (bp_inst)); + if (displ < 0 || displ > 3) + set_singlestep_breakpoint (serv, pc + displ, + &bp_inst, sizeof (bp_inst)); + + } + else + set_singlestep_breakpoint (serv, pc + 3, &bp_inst, sizeof (bp_inst)); + break; + + case 0xfa: + opcode = am33_read_byte (serv, pc + 1); + if (opcode == 0xff) + { + /* calls (d16,PC) */ + displ = am33_read_disp16 (serv, pc + 2); + set_singlestep_breakpoint (serv, pc + displ, + &bp_inst, sizeof (bp_inst)); + } + else + set_singlestep_breakpoint (serv, pc + 4, &bp_inst, sizeof (bp_inst)); + break; + + case 0xfc: + opcode = am33_read_byte (serv, pc + 1); + if (opcode == 0xff) + { + /* calls (d32,PC) */ + displ = am33_read_disp32 (serv, pc + 2); + set_singlestep_breakpoint (serv, pc + displ, &bp_inst, sizeof (bp_inst)); + } + else + set_singlestep_breakpoint (serv, pc + 6, &bp_inst, sizeof (bp_inst)); + break; + + } + + if (process->debug_backend) + fprintf (stderr, "PTRACE_CONT (am33): pid=%d signal=%d\n", pid, sig); + errno = 0; + ptrace (PTRACE_CONT, pid, 0, sig); + if (errno) + fprintf (stderr, "PTRACE_CONT (am33) error: %s in %d\n", + strerror (errno), pid); +} +#endif /* proc_service callback functions */ Index: ptrace-target.c =================================================================== RCS file: /cvs/src/src/rda/unix/ptrace-target.c,v retrieving revision 1.9 diff -u -p -r1.9 ptrace-target.c --- ptrace-target.c 30 Jun 2005 03:24:18 -0000 1.9 +++ ptrace-target.c 24 Aug 2005 01:12:08 -0000 @@ -161,7 +161,7 @@ handle_waitstatus (struct child_process return (process->stop_signal = WTERMSIG (w)); } -#if defined(_MIPSEL) || defined(_MIPSEB) +#if defined(_MIPSEL) || defined(_MIPSEB) || defined(AM33_2_0_LINUX_TARGET) /* * If we were single_stepping, restore the opcodes hoisted * for the breakpoint[s]. @@ -174,9 +174,19 @@ handle_waitstatus (struct child_process { ptrace_set_mem (process->serv, &process->ss_info[i].ss_addr, - &process->ss_info[i].ss_val, - sizeof (process->ss_info[i].ss_val)); + process->ss_info[i].ss_val, + process->ss_info[i].ss_size); process->ss_info[i].in_use = 0; + if (process->debug_backend) + { + long addr; + gdbserv_host_bytes_from_reg (process->serv, &addr, + sizeof (addr), + &process->ss_info[i].ss_addr, 0); + fprintf (stderr, + "Singlestep breakpoint %d cleared at location %lx\n", + i, addr); + } } process->is_ss = 0; } @@ -1239,7 +1249,7 @@ ptrace_attach (struct gdbserv *serv, voi ptrace_target->data = data; /* Save ptr to child_process struct. */ -#if defined(_MIPSEL) || defined(_MIPSEB) +#if defined(_MIPSEL) || defined(_MIPSEB) || defined(AM33_2_0_LINUX_TARGET) process->is_ss = 0; #endif @@ -1288,13 +1298,15 @@ int singlestep_lwp (struct gdbserv *serv, pid_t lwp, int signal) { -#if defined (MIPS_LINUX_TARGET) || defined (MIPS64_LINUX_TARGET) - { - if (thread_db_noisy) - fprintf (stderr, "\n", lwp, signal); - mips_singlestep (serv, lwp, signal); - return 0; - } +#if defined (AM33_2_0_LINUX_TARGET) + if (thread_db_noisy) + fprintf (stderr, "\n", lwp, signal); + am33_singlestep (serv, lwp, signal); + return 0; +#elif defined (MIPS_LINUX_TARGET) || defined (MIPS64_LINUX_TARGET) + if (thread_db_noisy) + fprintf (stderr, "\n", lwp, signal); + mips_singlestep (serv, lwp, signal); #else if (thread_db_noisy) fprintf (stderr, "\n", lwp, signal); Index: server.h =================================================================== RCS file: /cvs/src/src/rda/unix/server.h,v retrieving revision 1.3 diff -u -p -r1.3 server.h --- server.h 30 Jun 2005 03:24:18 -0000 1.3 +++ server.h 24 Aug 2005 01:12:08 -0000 @@ -24,7 +24,7 @@ /* Shared definitions for an RDA based native gdb server. */ -#if defined(_MIPSEL) || defined(_MIPSEB) +#if defined(_MIPSEL) || defined(_MIPSEB) || defined(AM33_2_0_LINUX_TARGET) /* * We single-step by setting breakpoints. When an exception * is handled, we need to restore the previous instructions @@ -35,7 +35,8 @@ struct ss_save { int in_use; struct gdbserv_reg ss_addr; - unsigned int ss_val; + char ss_val[8]; + int ss_size; }; #endif @@ -66,7 +67,7 @@ struct child_process { int debug_informational; int running; -#if defined(_MIPSEL) || defined(_MIPSEB) +#if defined(_MIPSEL) || defined(_MIPSEB) || defined(AM33_2_0_LINUX_TARGET) int is_ss; /* we are single stepping */ struct ss_save ss_info[2]; /* single stepping saved information */ #endif