Pointer values C not interpreted correctly?

Programming, for all ages and all languages.
scippie
Member
Member
Posts: 40
Joined: Wed Jun 27, 2012 3:57 am

Re: Pointer values C not interpreted correctly?

Post 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).
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Pointer values C not interpreted correctly?

Post 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.
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: Pointer values C not interpreted correctly?

Post 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.
"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: 4689
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Pointer values C not interpreted correctly?

Post 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.
scippie
Member
Member
Posts: 40
Joined: Wed Jun 27, 2012 3:57 am

Re: Pointer values C not interpreted correctly?

Post 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?
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Pointer values C not interpreted correctly?

Post 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?
scippie
Member
Member
Posts: 40
Joined: Wed Jun 27, 2012 3:57 am

Re: Pointer values C not interpreted correctly?

Post 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...
scippie
Member
Member
Posts: 40
Joined: Wed Jun 27, 2012 3:57 am

Re: Pointer values C not interpreted correctly?

Post 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...)
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Pointer values C not interpreted correctly?

Post 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?
scippie
Member
Member
Posts: 40
Joined: Wed Jun 27, 2012 3:57 am

Re: Pointer values C not interpreted correctly?

Post 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?
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Pointer values C not interpreted correctly?

Post 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.
scippie
Member
Member
Posts: 40
Joined: Wed Jun 27, 2012 3:57 am

Re: Pointer values C not interpreted correctly?

Post by scippie »

Ah.... thanks for clearing that up.
scippie
Member
Member
Posts: 40
Joined: Wed Jun 27, 2012 3:57 am

Re: Pointer values C not interpreted correctly?

Post 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)
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Pointer values C not interpreted correctly?

Post 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.
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: Pointer values C not interpreted correctly?

Post 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
"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 ]
Post Reply