Zulan
Zulan

Reputation: 22650

Tracing program/function execution on source line level

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).

Upvotes: 3

Views: 855

Answers (1)

Zulan
Zulan

Reputation: 22650

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()

Upvotes: 4

Related Questions