Skip to main content

Julia Evans

Day 44: qemu + gdb = so great

Today I did some more debugging and cleaning up. Previously I was setting up my IDT (interrupt descriptor table) with assembly, but I wanted to do it with Rust, because I don’t really know assembly and the less of it I have in my OS, the less of a liability it is. I’d tried to do this before, but it wasn’t working.

What turned out to be wrong:

  • I had 1 << 16 - 1 instead of (1 << 16) - 1, so my mask wasn’t working properly
  • I had the wrong function name for the interrupt handler
  • That was it!

This actually ended up being really easy to debug! “Really easy” as in “it took all day, but I did not feel like hiding under the table at any point”. I have a symbol table, and idt is in it, so I just needed to do iterations on

gdb) x/4x &idt

and compare the contents of memory from Working Code with the Non-Working Code.

x/ means “examine”, and 4x means “as hex, 4 times`. Here’s some documentation for examining memory.

Comparing sections of memory and figuring out why they’re wrong is tedious, but pretty straightforward – I had a good handle on what all my code was doing. Pretty exciting. Best friends, gdb.

gdb isn’t totally the best interface – I can certainly imagine having better ones. But it is Very Useful. So far I know how to

  • Find the address of a symbol in memory
  • Look at memory (as ints, as hex, as ASCII)
  • Search memory
  • Set breakpoints (and look at assembly that I don’t understand)
  • Make core dumps to look at later

These are pretty awesome superpowers already, and I’m sure there are tons more.

So now my interrupt handlers are set up in Rust! This will make it much easier for me to implement int 80, and therefore move towards being able to run programs! Excellent! Onwards!

Day 43: SOMETHING IS ERASING MY PROGRAM WHILE IT’S RUNNING (oh wait oops) Day 45: I now have Rust code for executing executables!