Page 1 of 1

GDB is incorrectly presenting global/static C variables

Posted: Tue Dec 15, 2020 2:40 pm
by itarato
Tl;dr - when using GDB and inspecting global or file static variables with `print var_name` - it will show value from a different memory location.

Example code:

Code: Select all

/// file1.c
static char buf[16];
// or
// char buf[16];

void foo() {
  buf[0] = 'x';
  // <- here GDB's `print buf` show garbage
}
At the mark `print buf` is not the actual `buf`'s memory. Listing the memory I usually able to find it not far from that point. If I print out the address of the memory of the var with `print &buf` I can see the incorrect address.
However all operations are correct. For example setting the variable (`buf[0] = ...`) is correct and I can load it with `... = buf[0]` as well as if I use `printf` from C code, that shows the correct value too - this is why I believe only GDB is confused about it.

Some observations:
- If I read the binary elf I can spot the variables assigned to the address that is not correct (eg 15: 00004100 8 OBJECT LOCAL DEFAULT 5 buf)
- this is the address above that GDB tells me where the variable is
- also this is the address where GDB prints out the memory when I use GDB's print
- looking at the disassembled code - the `movb ...` operations are working with the real and correct address

My setup is the following:
  • GCC flags: -g -Wall -Wextra -ffreestanding -fno-exceptions -pedantic -fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibs -m32
    Qemu: qemu-system-i386
    GDB is connected through TCP to Qemu
    Problem happens in 32bit protected mode (priv 0)
Same problem posted to stackoverflow (with details): https://stackoverflow.com/questions/651 ... c-variable

I definitely miss a lot of context here, I wonder where should I start looking for the fix.

Re: GDB is incorrectly presenting global/static C variables

Posted: Tue Dec 15, 2020 6:41 pm
by MichaelPetch
Do you have a github project somewhere or a way to see all the code, and a way to build it? It almost sounds like the location the data was loaded in memory was not where the code and debug info was expecting it. Are you sure you have properly loaded this code and data into memory so that it matches whatever VMA the code was built for?

Edit: I see in the SO comments you have a project here: https://github.com/itarato/VamOS

Re: GDB is incorrectly presenting global/static C variables

Posted: Tue Dec 15, 2020 8:20 pm
by MichaelPetch
I haven't investigated the reason for this but the linker produced different code when linking with `--format=binary` and without. I think it may be something related to you not using a linker script and instead relying on `-Ttext` to specify a VMA (origin point). As a result, the debug information in kernel.elf doesn't match the code actually being debugged. Modify your Makefile to use LD to link to an ELF executable and then use OBJCOPY to convert that ELF executable to a binary. The rules for kernel.elf and kernel.bin could be modified to look like:

Code: Select all

kernel.bin: kernel.elf
        i386-elf-objcopy -O binary $^ $@

kernel.elf: boot/kernel_entry.o ${OBJ}
        i386-elf-ld -o $@ -Ttext 0x1000 $^
Edit: It appears as if the alignment for the `.bss` section ended up being different between the two builds just by virtue of using `--format=binary`. I hadn't seen this behaviour in the past because I generally build the ELF executable with LD first and then use OBJCOPY to convert that ELF file to a binary file as I have done with the modifications of your Makefile. This at least ensures that the binary file generated from the actual ELF file produced.

Re: GDB is incorrectly presenting global/static C variables

Posted: Tue Dec 15, 2020 11:12 pm
by itarato
@MichaelPetch - thank you sooooo much. It did fix the issue. The elf file now has the same memory location as in the running code, as wall as GDB is now correct in all cases.
Saw your somment on SO - if you make it a reply I would love to mark it as an answer.