3

Is there a way, to record the execution of a particular function (or the entire program) in terms of the executed source code lines?

Consdier I set a breakpoint in gdb to function foo, and then repetedly call step, and it will tell me something like this:

(gdb) break foo
Thread 1 "main" hit Breakpoint 1, foo () at foo.cpp:10
(gdb) step
foo () at foo.cpp:12
(gdb) step
foo () at foo.cpp:13
(gdb) step
foo () at foo.cpp:12
(gdb) step
foo () at foo.cpp:14

Then I repeat that until foo is no longer in the output of bt. This gives me a trace of execution (foo.cpp:10->12->13->12->14), that is particularly useful to compare long control flows.

Is there a way to do this with gdb or is there another tool that does this? I am only interested in deterministic traces, not sampling. Ideally this could also be done for stepi (on instruction level) / next (without entering subroutines).

8
  • Looks like you debug stripped code or don't provide the source code. And that code is C++, not C. Commented Sep 20, 2016 at 19:30
  • In fact for this particular problem the source code is not available, but it is not stripped. Of course source line level would not be applicable for stripped binaries. I do strongly believe this question applies to both C and C++ and thus as per the C-tag wiki it is appropriate to tag both. The only difference would be demangling. If you remove the tag please indicate how a C answer wouldn't be appropriate for C++. Commented Sep 20, 2016 at 20:06
  • There seems to be a similar question with the difference being the end condition. Commented Sep 20, 2016 at 20:18
  • 1
    I am not sure I am answering your question (therefore it's a comment), but a usual way is to pair expect and gdb/mi (see sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI.html) Commented Sep 20, 2016 at 20:39
  • 1
    I think you can use the solutions in the question you linked to, but with the end condition ! $_caller_is ("foo", 0) (0 means to look only at the current frame). Commented Sep 20, 2016 at 21:04

1 Answer 1

4

Based on this similar question, I was able to put together a quick python script for my purpose. Fortunately with less required bug-workarounds:

import sys
import gdb
import os
import re

def in_frames(needle):
    """ Check if the passed frame is still on the current stack """
    hay = gdb.newest_frame()
    while hay:
        if hay == needle:
            return True
        hay = hay.older()
    return False

# Use this to reduce any kind of unwanted noise
def filter_step(output):
    output = re.sub(r'^.*No such file or directory\.\n', r'', output, flags=re.M)
    output = re.sub(r'^\d+\s+in\s+.*\n', r'', output, flags=re.M)
    return output

def step_trace(filename=None, step="step"):
    counter = 0
    if filename:
        output = ""
    frame = gdb.newest_frame()
    print("Stepping until end of {} @ {}:{}".format(frame.name(), frame.function().symtab, frame.function().line))
    while in_frames(frame):
        counter += 1
        if filename:
            output += filter_step(gdb.execute(step, to_string=True))
        else:
            gdb.execute(step)

    if filename:
        with open(filename, "w") as file:
            file.write(output)
    print("Done stepping through {} lines.".format(counter))

To output a trace to a file

(gdb) source step_trace.py
(gdb) python step_trace("filename.log")

or directly

(gdb) source step_trace.py
(gdb) python step_trace()
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.