Page 1 of 1

Debugging with gdb&qemu, breakpoints fail on virtual address

Posted: Wed Jul 03, 2013 4:27 am
by korepwx
I managed to setup virtual address for kernel via GDT on i386, however I found that GDB does not work properly when I debug it with QEMU.
Here is the skeleton of my source code:

https://github.com/korepwx/pcore/tree/b ... 972c3bf0e2

Bootloader does never setup a virtual memory address space. It simply load kernel into memory. My kernel.ld is like this (tools/kernel.ld):

Code: Select all

ENTRY(kern_entry)

SECTIONS {
    /* Load the kernel at this address: "." means the current address */
    . = 0xC0100000;
And, in bootmain.c, it loads the kernel into 0x100000 (and later call the routine) by doing this (boot/bootmain.c):

Code: Select all

for (; ph < eph; ph++) {
	readseg(ph->p_va & 0xFFFFFF, ph->p_memsz, ph->p_offset);
}
((void (*)(void))(ELFHDR->e_entry & 0xFFFFFF)) ();
When kern_entry (arch/i386/init/entry.S) is called, it soon sets up GDT for virtual address:

Code: Select all

.text
.globl kern_entry
kern_entry:
    # reload temperate gdt (second time) to remap all physical memory
    # virtual_addr 0~4G=linear_addr&physical_addr -KERNBASE~4G-KERNBASE 
    lgdt REALLOC(__gdtdesc)
    movl $KERNEL_DS, %eax
    movw %ax, %ds
    movw %ax, %es
    movw %ax, %ss

    ljmp $KERNEL_CS, $relocated
...

.align 4
__gdt:
    SEG_NULL
    SEG_ASM(STA_X | STA_R, - KERNBASE, 0xFFFFFFFF)      # code segment
    SEG_ASM(STA_W, - KERNBASE, 0xFFFFFFFF)              # data segment
And the kern_init routine (kern/init/init.cc):

Code: Select all

extern "C" {

  /**
   * @brief The main entry for kernel.
   * This method is called by bootloader; @sa boot/bootmain.c
   */
  int kern_init(void)
  {
    return 0;
  }
  
}
Everything works fine until I try to make GDB break at kern_init. GDB indeeds loads in symbol table, and tell me kern_init is at 0xC0100030. But GDB cannot break at 0xC0100030. What's more, if I tell GDB to stop at 0x100030, it works but can never recover from breakpoint.

Could anyone help me to figure out what's wrong with my code?

BTW, I'm using Qemu 1.4.0.

Re: Debugging with gdb&qemu, breakpoints fail on virtual add

Posted: Wed Jul 03, 2013 9:51 am
by Combuster
Are you sure you're debugging the content of the virtual machine, and not qemu itself?

Re: Debugging with gdb&qemu, breakpoints fail on virtual add

Posted: Wed Jul 03, 2013 10:09 am
by iansjack
I'm confused. You say you load the kernel at 0x1000000. So why do you expect it to be somewhere else? Sure you said it was in your linker file (which is probably what's confusing gdb) but you say you are not loading it to where you told the linker you would. So how would the code get there?

Re: Debugging with gdb&qemu, breakpoints fail on virtual add

Posted: Thu Jul 04, 2013 8:28 am
by korepwx
iansjack wrote:I'm confused. You say you load the kernel at 0x1000000. So why do you expect it to be somewhere else? Sure you said it was in your linker file (which is probably what's confusing gdb) but you say you are not loading it to where you told the linker you would. So how would the code get there?
So firstly, my bootloader load it in 0x100000, then calls the method in 0x100000.
At this time, Page table of x86 has not been set to serve virtual memory space.

Then, at the beginning of my kernel, I do these things:

Code: Select all

#define REALLOC(x) (x - KERNBASE)
.text
.globl kern_entry
kern_entry:
    # reload temperate gdt (second time) to remap all physical memory
    # virtual_addr 0~4G=linear_addr&physical_addr -KERNBASE~4G-KERNBASE 
    lgdt REALLOC(__gdtdesc)
    movl $KERNEL_DS, %eax
    movw %ax, %ds
    movw %ax, %es
    movw %ax, %ss
    ljmp $KERNEL_CS, $relocated

relocated:
    # set ebp, esp
    movl $0x0, %ebp
    # the kernel stack region is from bootstack -- bootstacktop,
    # the kernel stack size is KSTACKSIZE (8KB)defined in memlayout.h
    movl $bootstacktop, %esp
    # now kernel stack is ready , call the first C function
    call kern_init

...

__gdt:
    SEG_NULL
    SEG_ASM(STA_X | STA_R, - KERNBASE, 0xFFFFFFFF)      # code segment
    SEG_ASM(STA_W, - KERNBASE, 0xFFFFFFFF)              # data segment
__gdtdesc:
    .word 0x17                                          # sizeof(__gdt) - 1
    .long REALLOC(__gdt)
In the above codes, KERNBASE is set to 0xC0000000.

The bootloader loads the kernel into 0x100000, and calls 0x100000, so it indeed goes into kern_entry (which I see the correct disassembled instruction "lgdt" in GDB). Then, after the very beginning instruction of my Kernel, GDT is now set to serve virtual memory address, so all the symbol addresses defined by kernel.ld is now correct.

Just a simple use of x86 page table feature, I suppose. However, this feature may do confuse GDB. So my question is, how to let GDB support this virtual memory space, or to say x86 page table?

Re: Debugging with gdb&qemu, breakpoints fail on virtual add

Posted: Thu Jul 04, 2013 9:04 am
by iansjack
It may be that you are confusing gdb by setting the breakpoint before paging is set up then enabling paging. I'd say that you probably have to set the breakpoint after you have enabled paging and loaded the page table. It looks as if gdb is setting the breakpoint at the physical address because that's all that exists when you set the breakpoint. (Just my hypothesis, but it explains the result you are getting.)

Re: Debugging with gdb&qemu, breakpoints fail on virtual add

Posted: Thu Jul 04, 2013 9:22 am
by korepwx
iansjack wrote:It may be that you are confusing gdb by setting the breakpoint before paging is set up then enabling paging. I'd say that you probably have to set the breakpoint after you have enabled paging and loaded the page table. It looks as if gdb is setting the breakpoint at the physical address because that's all that exists when you set the breakpoint. (Just my hypothesis, but it explains the result you are getting.)
Yeah, I think so. But I very much want to debug with GDB & Qemu. So is there any workarounds?

Re: Debugging with gdb&qemu, breakpoints fail on virtual add

Posted: Thu Jul 04, 2013 12:15 pm
by iansjack
I use qemu/gdb for debugging, but my kernel code is identity mapped so I don't have this problem. I can only suggest that you set an initial breakpoint, using the physical address, shortly after paging is enabled. At that point you can try setting breakpoints using symbol names rather than physical addresses.