qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] Debugging vmlinux with qemu and gdb. Unable to step, ne


From: Edgar E. Iglesias
Subject: Re: [Qemu-devel] Debugging vmlinux with qemu and gdb. Unable to step, next, print or to get any information..
Date: Fri, 9 May 2008 10:38:41 +0200
User-agent: Mutt/1.5.16 (2007-06-09)

On Thu, May 08, 2008 at 11:39:11PM -0500, Jason Wessel wrote:
> Mulyadi Santosa wrote:
> > Hi...
> >
> > On Thu, May 8, 2008 at 2:53 PM, Keilhau Timo ( Student )
> > <address@hidden> wrote:
> >   
> >> Ive compiled the 2.6.25 kernel on guest with:
> >>  [*] Compile the kernel with frame pointers
> >>  [*] Compile the kernel with debug info
> >> additionally CFLAGS="-g3 -ggdb"
> >>     
> >
> > You meant -O3? well, IMO, you don't need -O at all. AFAIK mixing -g or
> > -ggdb with -O{1,2,3} is a bad thing, since it will render the DWARF
> > information inside the ELF file (in this case, the vmlinux)
> > inconsistent with the runtime context (line number, current EIP
> > correlated with break points).
> >
> > Of course, this assume that there is no bugs while Qemu inspect and
> > found that it must pause at certain address... I believe Jasson Wessel
> > had squashed all that kind of bugs in the past.
> >
> > regards,
> >
> > Mulyadi.
> >
> >   
> I believe that Mulyadi is talking about the following two patches which
> are attached here, assuming you are able to hit breakpoints.
> 
> Jason.
> 

Hi,

Tested the singlestepping w/o interrupts, it works very nice thanks.

Best regards


> From: Jason Wessel <address@hidden>
> Subject: [PATCH] Add x86_64 gdb stub for qemu
> 
> This patch comes from the kvm sources and allows debugging the back
> end with gdb connected to qemu for the qemu-system-x86_64 machine.
> 
> 
> Signed-off-by: Jason Wessel <address@hidden>
> 
> 
> ---
>  gdbstub.c |  134 
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 133 insertions(+), 1 deletion(-)
> 
> --- a/gdbstub.c
> +++ b/gdbstub.c
> @@ -238,9 +238,141 @@ static int put_packet(GDBState *s, char 
>      }
>      return 0;
>  }
> +#if defined(TARGET_X86_64)
>  
> -#if defined(TARGET_I386)
> +static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
> +{
> +    uint8_t *p = mem_buf;
> +    int i, fpus;
> +
> +#define PUTREG(x) do { \
> +       target_ulong reg = tswapl(x); \
> +       memcpy(p, &reg, sizeof reg); \
> +       p += sizeof reg; \
> +    } while (0)
> +#define PUTREG32(x) do { \
> +       uint32_t reg = tswap32(x);              \
> +       memcpy(p, &reg, sizeof reg); \
> +       p += sizeof reg; \
> +    } while (0)
> +#define PUTREGF(x) do { \
> +       memcpy(p, &(x), 10);                     \
> +       p += sizeof (x);                     \
> +    } while (0)
> +
> +    PUTREG(env->regs[R_EAX]);
> +    PUTREG(env->regs[R_EBX]);
> +    PUTREG(env->regs[R_ECX]);
> +    PUTREG(env->regs[R_EDX]);
> +    PUTREG(env->regs[R_ESI]);
> +    PUTREG(env->regs[R_EDI]);
> +    PUTREG(env->regs[R_EBP]);
> +    PUTREG(env->regs[R_ESP]);
> +    PUTREG(env->regs[8]);
> +    PUTREG(env->regs[9]);
> +    PUTREG(env->regs[10]);
> +    PUTREG(env->regs[11]);
> +    PUTREG(env->regs[12]);
> +    PUTREG(env->regs[13]);
> +    PUTREG(env->regs[14]);
> +    PUTREG(env->regs[15]);
> +
> +    PUTREG(env->eip);
> +    PUTREG32(env->eflags);
> +    PUTREG32(env->segs[R_CS].selector);
> +    PUTREG32(env->segs[R_SS].selector);
> +    PUTREG32(env->segs[R_DS].selector);
> +    PUTREG32(env->segs[R_ES].selector);
> +    PUTREG32(env->segs[R_FS].selector);
> +    PUTREG32(env->segs[R_GS].selector);
> +    /* XXX: convert floats */
> +    for(i = 0; i < 8; i++) {
> +        PUTREGF(env->fpregs[i]);
> +    }
> +    PUTREG32(env->fpuc);
> +    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
> +    PUTREG32(fpus);
> +    PUTREG32(0); /* XXX: convert tags */
> +    PUTREG32(0); /* fiseg */
> +    PUTREG32(0); /* fioff */
> +    PUTREG32(0); /* foseg */
> +    PUTREG32(0); /* fooff */
> +    PUTREG32(0); /* fop */
> +
> +#undef PUTREG
> +#undef PUTREG32
> +#undef PUTREGF
> +
> +    return p - mem_buf;
> +}
> +
> +static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int 
> size)
> +{
> +    uint8_t *p = mem_buf;
> +    uint32_t junk;
> +    int i, fpus;
> +
> +#define GETREG(x) do { \
> +       target_ulong reg; \
> +       memcpy(&reg, p, sizeof reg);     \
> +       x = tswapl(reg);               \
> +       p += sizeof reg;                 \
> +    } while (0)
> +#define GETREG32(x) do { \
> +       uint32_t reg; \
> +       memcpy(&reg, p, sizeof reg);     \
> +       x = tswap32(reg);               \
> +       p += sizeof reg;                 \
> +    } while (0)
> +#define GETREGF(x) do { \
> +       memcpy(&(x), p, 10);               \
> +       p += 10;                         \
> +    } while (0)
> +
> +    GETREG(env->regs[R_EAX]);
> +    GETREG(env->regs[R_EBX]);
> +    GETREG(env->regs[R_ECX]);
> +    GETREG(env->regs[R_EDX]);
> +    GETREG(env->regs[R_ESI]);
> +    GETREG(env->regs[R_EDI]);
> +    GETREG(env->regs[R_EBP]);
> +    GETREG(env->regs[R_ESP]);
> +    GETREG(env->regs[8]);
> +    GETREG(env->regs[9]);
> +    GETREG(env->regs[10]);
> +    GETREG(env->regs[11]);
> +    GETREG(env->regs[12]);
> +    GETREG(env->regs[13]);
> +    GETREG(env->regs[14]);
> +    GETREG(env->regs[15]);
> +
> +    GETREG(env->eip);
> +    GETREG32(env->eflags);
> +    GETREG32(env->segs[R_CS].selector);
> +    GETREG32(env->segs[R_SS].selector);
> +    GETREG32(env->segs[R_DS].selector);
> +    GETREG32(env->segs[R_ES].selector);
> +    GETREG32(env->segs[R_FS].selector);
> +    GETREG32(env->segs[R_GS].selector);
> +    /* XXX: convert floats */
> +    for(i = 0; i < 8; i++) {
> +        GETREGF(env->fpregs[i]);
> +    }
> +    GETREG32(env->fpuc);
> +    GETREG32(fpus); /* XXX: convert fpus */
> +    GETREG32(junk); /* XXX: convert tags */
> +    GETREG32(junk); /* fiseg */
> +    GETREG32(junk); /* fioff */
> +    GETREG32(junk); /* foseg */
> +    GETREG32(junk); /* fooff */
> +    GETREG32(junk); /* fop */
> +
> +#undef GETREG
> +#undef GETREG32
> +#undef GETREGF
> +}
>  
> +#elif defined(TARGET_I386)
>  static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
>  {
>      int i, fpus;

> From: Jason Wessel <address@hidden>
> Subject: [PATCH] debugger single step without interrupts
> 
> This patch allows the qemu backend debugger to single step an
> instruction without running the hardware interrupts.
> 
> 
> Signed-off-by: Jason Wessel <address@hidden>
> 
> ---
>  cpu-all.h     |    5 +++++
>  cpu-exec.c    |    2 +-
>  gdbstub.c     |   39 ++++++++++++++++++++++++++++++++++-----
>  qemu-doc.texi |   30 ++++++++++++++++++++++++++++++
>  vl.c          |    2 ++
>  5 files changed, 72 insertions(+), 6 deletions(-)
> 
> --- a/cpu-exec.c
> +++ b/cpu-exec.c
> @@ -422,7 +422,7 @@ int cpu_exec(CPUState *env1)
>  #if defined(TARGET_I386)
>                       && env->hflags & HF_GIF_MASK
>  #endif
> -                             ) {
> +            && !(env->singlestep_enabled & SSTEP_NOIRQ)) {
>                      if (interrupt_request & CPU_INTERRUPT_DEBUG) {
>                          env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
>                          env->exception_index = EXCP_DEBUG;
> --- a/vl.c
> +++ b/vl.c
> @@ -7508,6 +7508,7 @@ void main_loop_wait(int timeout)
>      qemu_aio_poll();
>  
>      if (vm_running) {
> +        if (!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER))
>          qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
>                          qemu_get_clock(vm_clock));
>          /* run dma transfers, if any */
> @@ -7515,6 +7516,7 @@ void main_loop_wait(int timeout)
>      }
>  
>      /* real time timers */
> +    if (!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER))
>      qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME],
>                      qemu_get_clock(rt_clock));
>  
> --- a/gdbstub.c
> +++ b/gdbstub.c
> @@ -73,6 +73,11 @@ typedef struct GDBState {
>  #endif
>  } GDBState;
>  
> +/* By default use no IRQs and no timers while single stepping so as to
> + * make single stepping like an ICE HW step.
> + */
> +static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER;
> +
>  #ifdef CONFIG_USER_ONLY
>  /* XXX: This is not thread safe.  Do we care?  */
>  static int gdbserver_fd = -1;
> @@ -940,7 +945,7 @@ static int gdb_handle_packet(GDBState *s
>              env->pc = addr;
>  #endif
>          }
> -        cpu_single_step(env, 1);
> +        cpu_single_step(env, sstep_flags);
>          gdb_continue(s);
>       return RS_IDLE;
>      case 'F':
> @@ -1047,9 +1052,34 @@ static int gdb_handle_packet(GDBState *s
>              goto breakpoint_error;
>          }
>          break;
> -#ifdef CONFIG_LINUX_USER
>      case 'q':
> -        if (strncmp(p, "Offsets", 7) == 0) {
> +    case 'Q':
> +        /* parse any 'q' packets here */
> +        if (!strcmp(p,"qemu.sstepbits")) {
> +            /* Query Breakpoint bit definitions */
> +            sprintf(buf,"ENABLE=%x,NOIRQ=%x,NOTIMER=%x",
> +                    SSTEP_ENABLE,
> +                    SSTEP_NOIRQ,
> +                    SSTEP_NOTIMER);
> +            put_packet(s, buf);
> +            break;
> +        } else if (strncmp(p,"qemu.sstep",10) == 0) {
> +            /* Display or change the sstep_flags */
> +            p += 10;
> +            if (*p != '=') {
> +                /* Display current setting */
> +                sprintf(buf,"0x%x", sstep_flags);
> +                put_packet(s, buf);
> +                break;
> +            }
> +            p++;
> +            type = strtoul(p, (char **)&p, 16);
> +            sstep_flags = type;
> +            put_packet(s, "OK");
> +            break;
> +        }
> +#ifdef CONFIG_LINUX_USER
> +        else if (strncmp(p, "Offsets", 7) == 0) {
>              TaskState *ts = env->opaque;
>  
>              sprintf(buf,
> @@ -1061,10 +1091,9 @@ static int gdb_handle_packet(GDBState *s
>              put_packet(s, buf);
>              break;
>          }
> -        /* Fall through.  */
>  #endif
> +        /* Fall through.  */
>      default:
> -        //        unknown_command:
>          /* put empty packet */
>          buf[0] = '\0';
>          put_packet(s, buf);
> --- a/cpu-all.h
> +++ b/cpu-all.h
> @@ -761,6 +761,11 @@ int cpu_watchpoint_insert(CPUState *env,
>  int cpu_watchpoint_remove(CPUState *env, target_ulong addr);
>  int cpu_breakpoint_insert(CPUState *env, target_ulong pc);
>  int cpu_breakpoint_remove(CPUState *env, target_ulong pc);
> +
> +#define SSTEP_ENABLE  0x1  /* Enable simulated HW single stepping */
> +#define SSTEP_NOIRQ   0x2  /* Do not use IRQ while single stepping */
> +#define SSTEP_NOTIMER 0x4  /* Do not Timers while single stepping */
> +
>  void cpu_single_step(CPUState *env, int enabled);
>  void cpu_reset(CPUState *s);
>  
> --- a/qemu-doc.texi
> +++ b/qemu-doc.texi
> @@ -1924,6 +1924,36 @@ Use @code{set architecture i8086} to dum
>  @code{x/10i $cs*16+$eip} to dump the code at the PC position.
>  @end enumerate
>  
> +Advanced debugging options:
> +
> +The default single stepping behavior is step with the IRQs and timer service 
> routines off.  It is set this way because when gdb executes a single step it 
> expects to advance beyond the current instruction.  With the IRQs and and 
> timer service routines on, a single step might jump into the one of the 
> interrupt or exception vectors instead of executing the current instruction. 
> This means you may hit the same breakpoint a number of times before executing 
> the instruction gdb wants to have executed.  Because there are rare 
> circumstances where you want to single step into an interrupt vector the 
> behavior can be controlled from GDB.  There are three commands you can query 
> and set the single step behavior:
> address@hidden @code
> address@hidden maintenance packet qqemu.sstepbits
> +
> +This will display the MASK bits used to control the single stepping IE:
> address@hidden
> +(gdb) maintenance packet qqemu.sstepbits
> +sending: "qqemu.sstepbits"
> +received: "ENABLE=1,NOIRQ=2,NOTIMER=4"
> address@hidden example
> address@hidden maintenance packet qqemu.sstep
> +
> +This will display the current value of the mask used when single stepping IE:
> address@hidden
> +(gdb) maintenance packet qqemu.sstep
> +sending: "qqemu.sstep"
> +received: "0x7"
> address@hidden example
> address@hidden maintenance packet Qqemu.sstep=HEX_VALUE
> +
> +This will change the single step mask, so if wanted to enable IRQs on the 
> single step, but not timers, you would use:
> address@hidden
> +(gdb) maintenance packet Qqemu.sstep=0x5
> +sending: "qemu.sstep=0x5"
> +received: "OK"
> address@hidden example
> address@hidden enumerate
> +
>  @node pcsys_os_specific
>  @section Target OS specific information
>  


-- 
Edgar E. Iglesias
Axis Communications AB




reply via email to

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