From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Juqq3-0008IT-Ab for qemu-devel@nongnu.org; Sat, 10 May 2008 11:18:19 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Juqq2-0008HW-4P for qemu-devel@nongnu.org; Sat, 10 May 2008 11:18:18 -0400 Received: from [199.232.76.173] (port=42418 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Juqq1-0008HJ-Lh for qemu-devel@nongnu.org; Sat, 10 May 2008 11:18:17 -0400 Received: from mail.windriver.com ([147.11.1.11]:64398 helo=mail.wrs.com) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1Juqq0-00058D-N4 for qemu-devel@nongnu.org; Sat, 10 May 2008 11:18:17 -0400 Message-ID: <4825BC9F.2080500@windriver.com> Date: Sat, 10 May 2008 10:17:51 -0500 From: Jason Wessel MIME-Version: 1.0 Subject: Re: [Qemu-devel] [PATCH] Fix broken PPC user space single stepping References: <4823D426.5090107@windriver.com> <20080509205328.GA21683@hall.aurel32.net> In-Reply-To: <20080509205328.GA21683@hall.aurel32.net> Content-Type: multipart/mixed; boundary="------------040808020406080803000507" Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Aurelien Jarno Cc: qemu-devel@nongnu.org This is a multi-part message in MIME format. --------------040808020406080803000507 Content-Type: text/plain; charset=ISO-8859-15 Content-Transfer-Encoding: 7bit Aurelien Jarno wrote: > On Thu, May 08, 2008 at 11:33:42PM -0500, Jason Wessel wrote: >> This patch also fixes the defect where branches were incorrectly >> calculated for the update to the env->nip when setting MSR_SE on >> a branch instruction. > > Please find my comments inside. > >> --- >> target-ppc/translate.c | 41 ++++++++++++++++++++++++++++++----------- >> 1 file changed, 30 insertions(+), 11 deletions(-) >> [clip] >> @@ -2803,8 +2806,17 @@ static always_inline void gen_goto_tb (D >> else >> #endif >> gen_op_b_T1(); >> - if (ctx->singlestep_enabled) >> - gen_op_debug(); >> + if (unlikely(ctx->singlestep_enabled)) { >> + if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) { >> + gen_update_nip(ctx, dest); >> + gen_op_debug(); >> + } else { >> + target_ulong tmp = ctx->nip; >> + ctx->nip = dest; >> + GEN_EXCP(ctx, POWERPC_EXCP_TRACE, 0); >> + ctx->nip = tmp; > > What's the point of generating POWERPC_EXCP_TRACE in gen_goto_tb()? > ctx->singlestep_enabled == CPU_SINGLE_STEP corresponds to MSR_SE, which > does not generate trace exception for branch instructions. > > MSR_BE does generate trace exception for branch instructions, but that's > already handled in gen_intermediate_code_internal() by testing > branch_step. But in this case that is not the way the hardware works. The linux kernel is only setting up the MSR_SE bit to step the instructions in user space for the PPC 6xx architecture. The 604 processor manual indicates (as well as when I tested it on real hardware) that the MSR_SE should generate a trace exception upon the completion of any instruction except for the "special cases" (see below). You have certainly pointed out a different problem however. I tested the MSR_BE functionality and it does not work at all for the same reason that the MSR_SE did not work with branches. The exception is generated in the wrong place, and the result is that the simulation stops at the wrong instruction when MSR_BE is set. To address this, I created a new patch which is attached. The new patch also fixes the case for using the qemu backend debugger and the MSR_SE or MSR_BE on the simulated cpu at the same time. The reference here for MSR_SE the single stepping is from: http://www-01.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF7785256996006E34F3/$file/604eUM_book.pdf --- from manual page 4-8 --- The processor generates a single-step trace exception upon the successful execution of the next instruction (unless that instruction is an rfi instruction). Successful execution means that the instruction caused no other exception. ------- And then there is the general 32bit ppc arch manual. http://www.freescale.com/files/product/doc/MPCFPE32B.pdf In there it states that the MSR_SE is an optional feature and that you should see the specific ppc part documentation, but it does further describe: --- from manual page 6-29 --- If this facility is implemented, a trace interrupt occurs when no higher priority interrupt exists and either of the conditions described above exist. The following are not traced: * rfi instruction * sc and trap instructions that trap * Other instructions that cause interrupts (other than trace interrupts) * The first instruction of any interrupt handler * Instructions that are emulated by software MSR[SE,BE] are both cleared when the trace interrupt is taken. In the normal use of this function, MSR[SE,BE] are restored when the interrupt handler returns to the interrupted program using an rfi instruction. ------ At least with these changes you can now more accurately debug a user space application with gdb running inside linux on the qemu-system-ppc as well as freely use the qemu backend debugger with single stepping. Jason. ps The "return;" just after the "out:" is there to eliminate some compiler warnings. This could be fixed by further changing all the "goto out;" statements with return; I had to move the ctx->exception type update prior to any calls to gen_goto_tb(), so the single step logic would apply correctly only in the branch case and not for any other kind of exception. I figured I'd limit the change scope to make the patch as readable as possible. --------------040808020406080803000507 Content-Type: text/x-patch; name="ppc_system_single_step.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="ppc_system_single_step.patch" From: Jason Wessel Subject: [PATCH] Fix ppc user space single stepping User space OS single stepping will hang a qemu instance because the instruction translation executes an internal debug exception that is meant for the qemu backend debugger. The test case is to use any program which executes a ptrace attach to a process and then "ptrace(PTRACE_SINGLESTEP,pid,0,0);". In general you could simply use gdb on the target and request it to "instruction step" a process with "si", so long as gdb is setup to not emulate single stepping with breakpoints. This patch splits the run-time single stepping from the debugger stub single stepping such that each type of single stepping gets the correct exception generation. This patch also fixes the defect where branches were incorrectly calculated for the update to the env->nip when setting MSR_SE or MSR_BE on a branch instruction. Signed-off-by: Jason Wessel --- target-ppc/translate.c | 60 +++++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 21 deletions(-) --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -29,6 +29,10 @@ #include "tcg-op.h" #include "qemu-common.h" +#define CPU_SINGLE_STEP 0x1 +#define CPU_BRANCH_STEP 0x2 +#define GDBSTUB_SINGLE_STEP 0x4 + /* Include definitions for instructions classes and implementations flags */ //#define DO_SINGLE_STEP //#define PPC_DEBUG_DISAS @@ -2785,7 +2789,7 @@ static always_inline void gen_goto_tb (D TranslationBlock *tb; tb = ctx->tb; if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) && - !ctx->singlestep_enabled) { + likely(!ctx->singlestep_enabled)) { tcg_gen_goto_tb(n); gen_set_T1(dest); #if defined(TARGET_PPC64) @@ -2803,8 +2807,20 @@ static always_inline void gen_goto_tb (D else #endif gen_op_b_T1(); - if (ctx->singlestep_enabled) - gen_op_debug(); + if (unlikely(ctx->singlestep_enabled)) { + if ((ctx->singlestep_enabled & + (CPU_BRANCH_STEP | CPU_SINGLE_STEP)) && + ctx->exception == POWERPC_EXCP_BRANCH) { + target_ulong tmp = ctx->nip; + ctx->nip = dest; + GEN_EXCP(ctx, POWERPC_EXCP_TRACE, 0); + ctx->nip = tmp; + } + if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) { + gen_update_nip(ctx, dest); + gen_op_debug(); + } + } tcg_gen_exit_tb(0); } } @@ -2824,6 +2840,7 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000 { target_ulong li, target; + ctx->exception = POWERPC_EXCP_BRANCH; /* sign extend LI */ #if defined(TARGET_PPC64) if (ctx->sf_mode) @@ -2842,7 +2859,6 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000 if (LK(ctx->opcode)) gen_setlr(ctx, ctx->nip); gen_goto_tb(ctx, 0, target); - ctx->exception = POWERPC_EXCP_BRANCH; } #define BCOND_IM 0 @@ -2857,6 +2873,7 @@ static always_inline void gen_bcond (Dis uint32_t bi = BI(ctx->opcode); uint32_t mask; + ctx->exception = POWERPC_EXCP_BRANCH; if ((bo & 0x4) == 0) gen_op_dec_ctr(); switch(type) { @@ -2985,12 +3002,14 @@ static always_inline void gen_bcond (Dis #endif gen_op_btest_T1(ctx->nip); no_test: - if (ctx->singlestep_enabled) + if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) { + gen_update_nip(ctx, ctx->nip); gen_op_debug(); + } tcg_gen_exit_tb(0); } out: - ctx->exception = POWERPC_EXCP_BRANCH; + return; } GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW) @@ -6150,7 +6169,6 @@ static always_inline int gen_intermediat target_ulong pc_start; uint16_t *gen_opc_end; int supervisor, little_endian; - int single_step, branch_step; int j, lj = -1; pc_start = tb->pc; @@ -6184,14 +6202,13 @@ static always_inline int gen_intermediat else ctx.altivec_enabled = 0; if ((env->flags & POWERPC_FLAG_SE) && msr_se) - single_step = 1; + ctx.singlestep_enabled = CPU_SINGLE_STEP; else - single_step = 0; + ctx.singlestep_enabled = 0; if ((env->flags & POWERPC_FLAG_BE) && msr_be) - branch_step = 1; - else - branch_step = 0; - ctx.singlestep_enabled = env->singlestep_enabled || single_step == 1; + ctx.singlestep_enabled |= CPU_BRANCH_STEP; + if (unlikely(env->singlestep_enabled)) + ctx.singlestep_enabled |= GDBSTUB_SINGLE_STEP; #if defined (DO_SINGLE_STEP) && 0 /* Single step trace mode */ msr_se = 1; @@ -6284,14 +6301,11 @@ static always_inline int gen_intermediat handler->count++; #endif /* Check trace mode exceptions */ - if (unlikely(branch_step != 0 && - ctx.exception == POWERPC_EXCP_BRANCH)) { - GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0); - } else if (unlikely(single_step != 0 && - (ctx.nip <= 0x100 || ctx.nip > 0xF00 || - (ctx.nip & 0xFC) != 0x04) && - ctx.exception != POWERPC_SYSCALL && - ctx.exception != POWERPC_EXCP_TRAP)) { + if (unlikely(ctx.singlestep_enabled & CPU_SINGLE_STEP && + (ctx.nip <= 0x100 || ctx.nip > 0xF00) && + ctx.exception != POWERPC_SYSCALL && + ctx.exception != POWERPC_EXCP_TRAP && + ctx.exception != POWERPC_EXCP_BRANCH)) { GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0); } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) || (env->singlestep_enabled))) { @@ -6307,6 +6321,10 @@ static always_inline int gen_intermediat if (ctx.exception == POWERPC_EXCP_NONE) { gen_goto_tb(&ctx, 0, ctx.nip); } else if (ctx.exception != POWERPC_EXCP_BRANCH) { + if (unlikely(env->singlestep_enabled)) { + gen_update_nip(&ctx, ctx.nip); + gen_op_debug(); + } /* Generate the return instruction */ tcg_gen_exit_tb(0); } --------------040808020406080803000507--