On Ubuntu?

If you're on Ubuntu, allow gdb to attach to running processes:

echo 0 > /proc/sys/kernel/yama/ptrace_scope

If you'd like that setting to remain across reboots:

vim /etc/sysctl.d/10-ptrace.conf

Update Makefile

Add the g flag to your jonesforth Makefile recipe:

jonesforth: jonesforth.S gcc -g -m32 -nostdlib -static $(BUILD_ID_NONE) -o $@ $<

Starting gdb

Then, start up jonesforth as usual in a terminal:

cat jonesforth.f - | ./jonesforth

In another terminal, start gdb and attach it to the running jonesforth:

gdb --quiet --pid=`pgrep jonesforth` ./jonesforth

Sample session

Here's what I see when I start gdb :

$ gdb --quiet --pid=`pgrep jonesforth` ./jonesforth Reading symbols from ./jonesforth...done. Attaching to program: /home/dharmatech/Dropbox/Documents/jonesforth-annexia/jonesforth, process 3406 _KEY () at jonesforth.S:1290 1290 test %eax,%eax // If %eax <= 0, then exit. (gdb)

Jonesforth is waiting for us to enter something. It's in the _KEY assembly routine. This is indicated by gdb above. It also shows that line 1290 is the next one to execute. Here's the _KEY routine:

_KEY: mov (currkey),%ebx cmp (bufftop),%ebx jge 1f // exhausted the input buffer? xor %eax,%eax mov (%ebx),%al // get next key from input buffer inc %ebx mov %ebx,(currkey) // increment currkey ret 1: // Out of input; use read(2) to fetch more input from stdin. xor %ebx,%ebx // 1st param: stdin mov $buffer,%ecx // 2nd param: buffer mov %ecx,currkey mov $BUFFER_SIZE,%edx // 3rd param: max length mov $__NR_read,%eax // syscall: read int $0x80 test %eax,%eax // If %eax <= 0, then exit. jbe 2f addl %eax,%ecx // buffer+%eax = bufftop mov %ecx,bufftop jmp _KEY 2: // Error or end of input: exit the program. xor %ebx,%ebx mov $__NR_exit,%eax // syscall: exit int $0x80

_KEY uses some variables in memory: buffer , currkey , and bufftop . It also uses a couple of registers. Let's use gdb 's Auto Display feature to display these:

display/8cb &buffer display/1xw &currkey display/1xw &bufftop display/x $eax display/x $ebx

Now if we type display in gdb , we'll see all of those at once:

(gdb) display 1: x/8cb &buffer 0x804c000: 97 'a' 98 'b' 108 'l' 121 'y' 46 '.' 32 ' ' 32 ' ' 84 'T' 2: x/xw &currkey 0x8049d54: 0x0804c000 3: x/xw &bufftop 0x8049d58: 0x0804c7e3 4: /x $eax = 0xfffffe00 5: /x $ebx = 0x0

This might also be a good time to enable gdb 's TUI:

tui enable

gdb should now look like this:

OK, jonesforth is still waiting for input. So let's give it something:

JONESFORTH VERSION 47 14499 CELLS REMAINING OK 123

Alright, back in gdb, we can finally ask it to step:

(gdb) s 1: x/8cb &buffer 0x804c000: 49 '1' 50 '2' 51 '3' 10 '

' 46 '.' 32 ' ' 32 ' ' 84 'T' 2: x/xw &currkey 0x8049d54: 0x0804c000 3: x/xw &bufftop 0x8049d58: 0x0804c7e3 4: /x $eax = 0x4 5: /x $ebx = 0x0

Hey, look at that! The first 3 characters in buffer are 1 , 2 , and 3 .

If %eax <= 0 the next step will jump to the 2f label. But as we can see above, %eax is 4 . So it should just continue on.

If we step through the next three lines, the bufftop will be set to the address of buffer incremented by 4 (three characters of '123' plus a newline character). The value in relation to the address of buffer checks out:

3: x/xw &bufftop 0x8049d58: 0x0804c004

Now that data has been read into the input buffer, _KEY will do its job and return back to the caller. Here's the next few instructions before the return:

As you step through those, the auto display feature will show the variables and registers updating accordingly.