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?

SurvivalMachine
  • 7,946
  • 15
  • 57
  • 87
  • What values DO you get? And what's the base address of your executable? – ssbssa Jan 20 '21 at 11:29
  • @ssbssa myPrint's low_pc is `0x00001181`. I read the base address by taking the address in the first line of `pmap -x pid` and it's `0000555555554000`. But my program counter never has values near the base address, it's always something like `0x7ffff7ecf1e7`. – SurvivalMachine Jan 21 '21 at 14:32
  • And what does `info files` in gdb say? – ssbssa Jan 21 '21 at 16:32
  • @ssbssa `info files` tells me that the entry point is `0x555555555060`. – SurvivalMachine Jan 22 '21 at 17:55
  • But does it show you where `0x7ffff7ecf1e7` belongs to? – ssbssa Jan 22 '21 at 18:56
  • @ssbssa I guess it's inside .text segment: `0x00007ffff7fd0100 - 0x00007ffff7ff25e4 is .text in /lib64/ld-linux-x86-64.so.2`. So I seem to be only getting addresses inside some libraries, not my executable. – SurvivalMachine Jan 23 '21 at 06:07
  • I think if your program actually did something that takes some time, you will get different results. – ssbssa Jan 23 '21 at 11:22

1 Answers1

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.

SurvivalMachine
  • 7,946
  • 15
  • 57
  • 87