Debugging with gdb&qemu, breakpoints fail on virtual address

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
korepwx
Posts: 3
Joined: Wed Jul 03, 2013 4:09 am

Debugging with gdb&qemu, breakpoints fail on virtual address

Post 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.
Attachments
However, GDB does break on 0x100030. This works same whether I setup the breakpoint before lgdt or after lgdt.
However, GDB does break on 0x100030. This works same whether I setup the breakpoint before lgdt or after lgdt.
GDB does not break on 0xC0100030.
GDB does not break on 0xC0100030.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

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

Post by Combuster »

Are you sure you're debugging the content of the virtual machine, and not qemu itself?
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
iansjack
Member
Member
Posts: 4711
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

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

Post 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?
User avatar
korepwx
Posts: 3
Joined: Wed Jul 03, 2013 4:09 am

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

Post 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?
User avatar
iansjack
Member
Member
Posts: 4711
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

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

Post 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.)
User avatar
korepwx
Posts: 3
Joined: Wed Jul 03, 2013 4:09 am

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

Post 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?
User avatar
iansjack
Member
Member
Posts: 4711
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

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

Post 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.
Post Reply