qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Possible bug in Aarch64 single-stepping [PATCH]


From: Chris Howard
Subject: Re: Possible bug in Aarch64 single-stepping [PATCH]
Date: Sun, 8 May 2022 21:27:27 +0200

On 8. May 2022, at 14:18, Peter Maydell <peter.maydell@linaro.org> wrote:

> On Sat, 7 May 2022 at 15:18, Chris Howard <cvz185@web.de> wrote:
>> PS. In plain gdb (ie. no nice user interface) a large number (but not all) 
>> of the system registers gets displayed after each step. It would be nice if 
>> these were sorted in some way. At the moment they’re completely jumbled — 
>> not alphabetic, not grouped by EL, nor by “meaning”  (DBGWVR0_EL1 isn’t 
>> necessarily next to DBGWCR0_EL1).
>> 
>> Also, there are multiple (identical?) instances of “DBGBVR” and “DBGBCR” 
>> (and  “DBGWVR” and “DBGWCR”) rather than the expected “DBGWVR0_EL1”, 
>> “DBGWVR1_EL1” etc.
>> 
>> Would this be a QEMU or a GDB issue? Or isn’t it an issue at all? :-)
> 
> My gdb doesn't do that. Basically QEMU provides gdb with some XML
> telling it that the sysregs are present, but it's up to gdb at
> what points it chooses to display what registers and how it does that.
> 
> The system register read access via the gdbstub is "best-effort"
> on QEMU's part -- we implement it to the extent that it wasn't too
> difficult to do, but there are some sharp edges, like the
> register names not always being quite right, and also the way
> that if you try to read a register that isn't supposed to be
> accessible by the current EL you might find it's not correct.
> Trying to read SP_EL2 while at EL2 is an example of that.
> 
> The reason register names are sometimes funny is that the
> infrastructure for system registers within QEMU was originally
> written with the assumption that the name strings were merely
> for convenience when debugging QEMU itself, so it's sometimes
> a bit careless about them. We only added the "tell GDB about
> these" part later.
> 
> That said, adding the numbers into the watchpoint and breakpoint
> registers would be pretty easy, so we should do that. That is,
> in this code:
> https://gitlab.com/qemu-project/qemu/-/blob/master/target/arm/helper.c#L6567
> we should use g_strdup_printf() to create unique per-register
> names, the same way we do for the PMU registers already here:
> https://gitlab.com/qemu-project/qemu/-/blob/master/target/arm/helper.c#L6632
> 
> thanks
> -- PMM

Thanks for the explanation. What with this being “pretty easy” I’m attempting 
my first ever patch!  :-)

BE WARNED!

This is a context diff with respect to the cloned git repository (Version 
7.0.50)

$ git clone https://gitlab.com/qemu-project/qemu.git

created with

$ diff -c qemu/target/arm/helper.c qemu-patch/target/arm/helper.c > 
aarch-dbg-regnames.patch

to be applied (in the target/arm directory) with

$ patch -p3 <../../../aarch-dbg-regnames.patch


— chris


 
*** qemu/target/arm/helper.c    2022-05-08 20:41:48.000000000 +0200
--- qemu-patch/target/arm/helper.c      2022-05-08 20:55:25.000000000 +0200
***************
*** 6551,6559 ****
          define_one_arm_cp_reg(cpu, &dbgdidr);
      }
  
!     /* Note that all these register fields hold "number of Xs minus 1". */
!     brps = arm_num_brps(cpu);
!     wrps = arm_num_wrps(cpu);
      ctx_cmps = arm_num_ctx_cmps(cpu);
  
      assert(ctx_cmps <= brps);
--- 6551,6559 ----
          define_one_arm_cp_reg(cpu, &dbgdidr);
      }
  
!     /* Note that all these reg fields (in ID_AA64DFR0_EL1) hold "number of Xs 
minus 1". */
!     brps = arm_num_brps(cpu);                 /* returns actual number of 
breakpoints */
!     wrps = arm_num_wrps(cpu);                 /* returns actual number of 
watchpoints */
      ctx_cmps = arm_num_ctx_cmps(cpu);
  
      assert(ctx_cmps <= brps);
***************
*** 6565,6578 ****
      }
  
      for (i = 0; i < brps; i++) {
          ARMCPRegInfo dbgregs[] = {
!             { .name = "DBGBVR", .state = ARM_CP_STATE_BOTH,
                .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 4,
                .access = PL1_RW, .accessfn = access_tda,
                .fieldoffset = offsetof(CPUARMState, cp15.dbgbvr[i]),
                .writefn = dbgbvr_write, .raw_writefn = raw_write
              },
!             { .name = "DBGBCR", .state = ARM_CP_STATE_BOTH,
                .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 5,
                .access = PL1_RW, .accessfn = access_tda,
                .fieldoffset = offsetof(CPUARMState, cp15.dbgbcr[i]),
--- 6565,6580 ----
      }
  
      for (i = 0; i < brps; i++) {
+               char *dbgbvr_el1_name = g_strdup_printf("DBGBVR%d_EL1", i);
+               char *dbgbcr_el1_name = g_strdup_printf("DBGBCR%d_EL1", i);
          ARMCPRegInfo dbgregs[] = {
!             { .name = dbgbvr_el1_name, .state = ARM_CP_STATE_BOTH,
                .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 4,
                .access = PL1_RW, .accessfn = access_tda,
                .fieldoffset = offsetof(CPUARMState, cp15.dbgbvr[i]),
                .writefn = dbgbvr_write, .raw_writefn = raw_write
              },
!             { .name = dbgbcr_el1_name, .state = ARM_CP_STATE_BOTH,
                .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 5,
                .access = PL1_RW, .accessfn = access_tda,
                .fieldoffset = offsetof(CPUARMState, cp15.dbgbcr[i]),
***************
*** 6580,6596 ****
              },
          };
          define_arm_cp_regs(cpu, dbgregs);
      }
  
      for (i = 0; i < wrps; i++) {
          ARMCPRegInfo dbgregs[] = {
!             { .name = "DBGWVR", .state = ARM_CP_STATE_BOTH,
                .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 6,
                .access = PL1_RW, .accessfn = access_tda,
                .fieldoffset = offsetof(CPUARMState, cp15.dbgwvr[i]),
                .writefn = dbgwvr_write, .raw_writefn = raw_write
              },
!             { .name = "DBGWCR", .state = ARM_CP_STATE_BOTH,
                .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 7,
                .access = PL1_RW, .accessfn = access_tda,
                .fieldoffset = offsetof(CPUARMState, cp15.dbgwcr[i]),
--- 6582,6602 ----
              },
          };
          define_arm_cp_regs(cpu, dbgregs);
+         g_free(dbgbvr_el1_name);
+         g_free(dbgbcr_el1_name);
      }
  
      for (i = 0; i < wrps; i++) {
+               char *dbgwvr_el1_name = g_strdup_printf("DBGWVR%d_EL1", i);
+               char *dbgwcr_el1_name = g_strdup_printf("DBGWCR%d_EL1", i);
          ARMCPRegInfo dbgregs[] = {
!             { .name = dbgwvr_el1_name, .state = ARM_CP_STATE_BOTH,
                .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 6,
                .access = PL1_RW, .accessfn = access_tda,
                .fieldoffset = offsetof(CPUARMState, cp15.dbgwvr[i]),
                .writefn = dbgwvr_write, .raw_writefn = raw_write
              },
!             { .name = dbgwcr_el1_name, .state = ARM_CP_STATE_BOTH,
                .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 7,
                .access = PL1_RW, .accessfn = access_tda,
                .fieldoffset = offsetof(CPUARMState, cp15.dbgwcr[i]),
***************
*** 6598,6603 ****
--- 6604,6611 ----
              },
          };
          define_arm_cp_regs(cpu, dbgregs);
+         g_free(dbgwvr_el1_name);
+         g_free(dbgwcr_el1_name);
      }
  }
  




reply via email to

[Prev in Thread] Current Thread [Next in Thread]