Page 2 of 3
Re: Pointer values C not interpreted correctly?
Posted: Tue Feb 05, 2013 3:34 pm
by scippie
iansjack wrote:Run your code in qemu with debugging enabled. Use gdb and single-step throught the code. The problem should then reveal itself.
bluemoon wrote:have you actually see what's executing on the debugger?
So I took your advise and I installed qemu and gdb. Qemu emulates my disk perfectly. Gdb can connect to qemu. But the problem is that I can't place breakpoints.
Somewhere on the internet I found out that this is because when starting qemu in suspended mode, it is still in real mode, gdb will think in real-mode. So if I create a breakpoint on a specific address, gdb will put it in real mode. When I arrive in x64-mode at that address, something does happen at that address, but gdb will totally freak out and I can't do anything interesting at that point.
Do you know how I can start qemu not suspended but make gdb break at the address I want? I tried putting int 3 in the code, I tried using the DR0 register, nothing seems to work (or I don't know how to do it correctly).
Re: Pointer values C not interpreted correctly?
Posted: Tue Feb 05, 2013 4:13 pm
by bluemoon
The problem with gdb and qemu running 64-bit kernel is that the gdb-stub is not aware for the 32->64bit mode switching, and messed up machine state & register contents when you do things like
info registers.
It is however possible to put breakpoints, but in your case since you're using flat binary you need to provide the symbolic table for gdb to look up the symbols, or otherwise put breakpoint at memory address - a good place would be the entry point of your kernel.
If the kernel entry breakpoint is not triggered, try put it on 0000:7C00 and trace where you loaded (and jumped to) the kernel.
I tried putting int 3 in the code, I tried using the DR0 register, nothing seems to work (or I don't know how to do it correctly).
Doing INT 3 has nothing to do with debugger, but it would just invoke your interrupt handler - unless your handler itself invoke gdb stub.
I'm not familiar with DR0 register so I can't comment on that.
By the way, another useful debug skill is printf, for kernel it's trivial to print a character on different position on screen for different checkpoint; it's also good idea to dump message to serial port and configure the emulator to attach to its input/output.
Re: Pointer values C not interpreted correctly?
Posted: Tue Feb 05, 2013 4:29 pm
by Combuster
You can forget about having hardware debugger stuff working in emulators - it'd make things just too slow so it's not implemented. (unless you have bochs and explicitly enable it at compile-time for that purpose)
Speaking of bochs, it has much better system debugging capabilities than the authors of gdb the application debugger ever care for - including stats of peripheral hardware. Also, compiling your own with debugger will get you something that just works instead of needing to mess with gdb architectures and whatnot.
Re: Pointer values C not interpreted correctly?
Posted: Tue Feb 05, 2013 4:48 pm
by iansjack
As well as the raw-binary version of your kernel you can also produce an elf object-file version with debugging symbols. You can then load this to use for debugging. There are difficulties because of the 32-64 bit switch. I set a breakpoint at an address when I know the program is in 64-bit mode (break *0x12345, for example) then "load kernel.o" to get the debugging symbols. Then I can single-step through the C code. (If you just want to single-step through assembler code you don't need any symbols.)
Actually, it's easier now that I have a shell loading and running reliably. I just start the program and then break with <ctrl>-C when the prompt appears. Then I load the symbols from kernel.o and can set breakpoints at function names and/or source-code line numbers.
In the early days, to be able to debug right from the start of the boot loader, I used the program SimNow. That provides an excellent debugger for assembler and handles the switch from 16-32-64 bit modes without any problems. Again you set a breakpoint at a specific address before the bit of code that you want to examine. It's slower than qemu, and is no good for debugging at C-code level, but provides a much easier-to-use interface than gdb for debugging at the lowest level.
Re: Pointer values C not interpreted correctly?
Posted: Wed Feb 06, 2013 8:15 am
by scippie
Ok, so I'm still trying to figure out what's going wrong, and since I still haven't gotten any luck with debugging (tried everything you guys said, no luck...), I have been looking at some assembly code, which has been disassembled from the linked flat binary.
Code: Select all
unsigned long idx = 0xdeadbeaf;
void main(void)
{
printhex((unsigned long)&idx);
}
seems to disassemble to:
Code: Select all
1a43: 48 8b 05 b6 1f 00 00 mov 0x1fb6(%rip),%rax # 0x3a00
1a4a: 48 89 c7 mov %rax,%rdi
1a4d: e8 05 00 00 00 callq 0x1a57
and
Code: Select all
unsigned long idx = 0xdeadbeaf;
void main(void)
{
printhex(idx);
}
seems to disassemble to:
Code: Select all
1a43: 48 8b 05 b6 1f 00 00 mov 0x1fb6(%rip),%rax # 0x3a00
1a4a: 48 8b 00 mov (%rax),%rax
1a4d: 48 89 c7 mov %rax,%rdi
1a50: e8 05 00 00 00 callq 0x1a5a
Isn't this completely wrong? I have trouble reading GAS (I'm a FASM man), but as far as I can read it, it seems like the NON-&-code does a & and the &-code doesn't???
As far as I can read, the NON-& code does this:
- put the data at address RIP + 0x1fb6 in the RAX register (adress is correct)
- take the value at address RAX and put it in RAX
- copy the recovered value in RAX to RDI
- and call the printhex function which seems to put the value in RDI into the stack and starts working with it.
But this is the code that should be generated on the &-code, not the NON-& code which seems to do the opposite.
This gives me a reason to understand why an exception occurs: it's trying to read the value at address 0xdeadbeef which isn't accessible.
When you look at the &-code:
- put the data at address RIP + 0x1fb6 in the RAX register
- copy the value in RAX to RDI
- call printhex
In other words: somehow it looks like C is misinterpreting the unsigned long variable as some kind of pointer, but not really?
I am quite sure gcc doesn't have bugs like that, so what is going wrong then?
Or am I misinterpreting the assembly code?
Re: Pointer values C not interpreted correctly?
Posted: Wed Feb 06, 2013 8:20 am
by bluemoon
Code: Select all
unsigned long idx = 0xdeadbeaf;
void main(void)
{
printhex(idx);
}
1a43: 48 8b 05 b6 1f 00 00 mov 0x1fb6(%rip),%rax # 0x3a00
1a4a: 48 8b 00 mov (%rax),%rax # rax = [0x3A00] = 0xdeadbeaf
1a4d: 48 89 c7 mov %rax,%rdi
1a50: e8 05 00 00 00 callq 0x1a5a
Which part you think is wrong?
Re: Pointer values C not interpreted correctly?
Posted: Wed Feb 06, 2013 8:21 am
by scippie
scippie wrote:This gives me a reason to understand why an exception occurs: it's trying to read the value at address 0xdeadbeef which isn't accessible.
Changing 0xdeadbeef to 0xdead gives me 0 as result, not an exception, this seems more or less proof of this theory...
Re: Pointer values C not interpreted correctly?
Posted: Wed Feb 06, 2013 8:23 am
by scippie
bluemoon wrote:Code: Select all
unsigned long idx = 0xdeadbeaf;
void main(void)
{
printhex(idx);
}
1a43: 48 8b 05 b6 1f 00 00 mov 0x1fb6(%rip),%rax # 0x3a00
1a4a: 48 8b 00 mov (%rax),%rax # rax = [0x3A00] = 0xdeadbeaf
1a4d: 48 89 c7 mov %rax,%rdi
1a50: e8 05 00 00 00 callq 0x1a5a
Which part you think is wrong?
Doesn't the first line put the value at address [rip + 0x1fb6] in rax?
(which is actually what I'm seeing...)
Re: Pointer values C not interpreted correctly?
Posted: Wed Feb 06, 2013 8:38 am
by bluemoon
Yes, the first line resolve the address of idx, and the second line de-reference it and get the value 0xdeadbeaf, which part you don't understand?
Re: Pointer values C not interpreted correctly?
Posted: Wed Feb 06, 2013 8:43 am
by scippie
bluemoon wrote:Yes, the first line resolve the address of idx, and the second line de-reference it and get the value 0xdeadbeaf, which part you don't understand?
What I'm saying is: doesn't the first line already take 0xdeadbeef out of the memory?
When I see: mov (%rax), %rax, it tells me to take the value of rax as an address, read at the memory location at address [rax] and put that value in rax. This is what it actually does, right?
So when I see: mov (%rip), %rax, i think: it takes address rip, reads memory at that address and puts it in rax. In other words, if this instruction is at address 0x1000, I would expect rax to be the machine code at this address.
So when I see: mov 0x100(%rip), %rax), I think: it takes address rip+0x100, reads memory at that address and puts it in rax. So in other words, if this instruction is at address 0x1000, I would expect rax to be the machine code at address 0x1100.
But that's not what's happening then?
Re: Pointer values C not interpreted correctly?
Posted: Wed Feb 06, 2013 8:59 am
by bluemoon
I see your confusion.
mov 0x1fb6(%rip),%rax is getting the content from the GOT entry, which hold the relocated address of idx.
Re: Pointer values C not interpreted correctly?
Posted: Wed Feb 06, 2013 9:21 am
by scippie
Ah.... thanks for clearing that up.
Re: Pointer values C not interpreted correctly?
Posted: Wed Feb 06, 2013 10:18 am
by scippie
bluemoon wrote:getting the content from the GOT entry, which hold the relocated address of idx.
Oh, but wait, then this might be the actual problem. Where is this GOT in my flat binary?
I mean, if I interpret rip, 0x1a4a gotten from disassembly, and add 0x1fb6 to it, I get 0x3a00. When I look in my memory at that address, I see my variable contents: DEADBEEF. But this should be a pointer to the variable containing DEADBEEF then?? If that is true, then the effect I am seeing is totally correct of course: address being deadbeef, value giving exception.
Am I missing some point here?
(I must admit that I have never heard of a GOT before, although I immediately assumed it was what it is)
Re: Pointer values C not interpreted correctly?
Posted: Wed Feb 06, 2013 12:52 pm
by bluemoon
This is going to beyond my imagination as I don't used flat binary at all, but as you truncated crucial information to produce flat binary I cannot see how GOT object are handled. I hope someone else experienced with flat binary can explain the issue.
Re: Pointer values C not interpreted correctly?
Posted: Wed Feb 06, 2013 3:50 pm
by Combuster
it's rather the -fPIC option that gets you into that mess because it means "individual sections can be moved" rather than the app as a whole which makes it rather braindead for your purposes. It also implies the need for a runtime linker