How to check if my debugger's program counter is inside a function?

0

I'm writing a debugger and want to see if its program counter is inside a function. I guess I need to check that it's between DW_AT_low_pc and DW_AT_high_pc. Here's the code I'm trying to debug:

void myPrint()
{
    int test_a = 3;
    int test_b = 2;

    printf( "myPrint: sum: %d\n", test_a + test_b );
}

int main( void )
{
    myPrint();

    return 0;
}

dwarfdump gives the following:

< 1><0x0000033d>    DW_TAG_subprogram
                      DW_AT_external              yes(1)
                      DW_AT_name                  myPrint
                      DW_AT_decl_file             0x00000001 /home/glaze/Documents/src/debugger/test_input.c
                      DW_AT_decl_line             0x0000000d
                      DW_AT_decl_column           0x00000006
                      DW_AT_low_pc                0x00001181
                      DW_AT_high_pc               <offset-from-lowpc>66
                      DW_AT_frame_base            len 0x0001: 9c: DW_OP_call_frame_cfa
                      DW_AT_GNU_all_tail_call_sites yes(1)
                      DW_AT_sibling               <0x0000037a>

In my debugger loop I read the program counter as follows:

    struct user_regs_struct regs;
    if (ptrace( PTRACE_GETREGS, pid, 0, &regs ) == -1)
    {
        printf( "%s", strerror( errno ) );
        return 1;
    }

    Elf64_Addr programCounter = regs.rip;

But it gets values that are never between DW_AT_low_pc and DW_AT_high_pc, like 0x7f9b94c95100.

I can already programmatically read DW_AT_low_pc and DW_AT_high_pc inside my debugger program and it reports the same values as dwarfdump.

How do I check that my program counter is inside myPrint function?

c
linux
gcc
dwarf

1 Answer

0

I solved this by taking the program's base address by reading the first line of /proc/pid/maps and adding it to DW_AT_low_pc. DW_AT_high_pc is an offset from DW_AT_low_pc.

Then in my debugger loop I ran it single-stepped with

ptrace( PTRACE_SINGLESTEP, pid, NULL, NULL );

At each iteration, I checked that the program counter regs.rip is between the function address range.

Debugging the issue was easier when I compiled the test program with -g -fno-pic -O0 -fPIE and in the debugger program disabled address space randomization by calling personality( ADDR_NO_RANDOMIZE ); just before ptrace( PTRACE_TRACEME, 0, NULL, NULL );. I also made the test program more complex by writing a simple adding loop so that it does also something else than calling library routines like printf() whose addresses are outside of my executable.

answered on Stack Overflow Jan 30, 2021 by SurvivalMachine

User contributions licensed under CC BY-SA 3.0