Skip to content

Instantly share code, notes, and snippets.

@briandw
Last active March 6, 2024 00:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save briandw/a07a9974db06fd148ff43ae329a7825d to your computer and use it in GitHub Desktop.
Save briandw/a07a9974db06fd148ff43ae329a7825d to your computer and use it in GitHub Desktop.
Compile a c program with Clang, debug it with LLDB and trap at a function. Why doesn't the line number match?
from pathlib import Path
import lldb
import os
from lldb import SBError, SBThread, SBFrame
def main():
c_code = """#include <stdio.h>
struct recursive_struct; //forward declaration.
//function pointer type
typedef void (*function_pointer_type)(struct recursive_struct *, int);
//Struct type with a pointer to itself
struct recursive_struct
{
char **data;
int data_size;
struct recursive_struct *next;
// function pointer type
function_pointer_type function_pointer;
};
typedef struct recursive_struct recursive_struct_type;
void init_bar(recursive_struct_type *b, char **data, int data_size){
b->data = data;
b->data_size = data_size;
}
void print_bar(recursive_struct_type *b){
printf("%d ", b->data_size);
}
int main(void){
char *data[] = {"Hello", "World!", NULL};
recursive_struct_type b;
init_bar(&b, data, 2);
print_bar(&b);
printf("Data size: %d\\n", b.data_size);
return 0;
}
"""
#Compile the main code
main_file = Path("main.c")
main_file.write_text(c_code)
os.system('clang -g -O0 main.c -o main')
debugger = lldb.SBDebugger.Create()
debugger.SetAsync(False)
target = debugger.CreateTarget("main")
function_name_breakpoint = "init_bar"
break_point_main = target.BreakpointCreateByName(function_name_breakpoint)
launch_info = lldb.SBLaunchInfo(["./main"])
launch_info.SetWorkingDirectory(os.getcwd())
error = SBError()
process = target.Launch(launch_info, error)
assert target.IsValid()
assert process.IsValid()
assert break_point_main.IsValid()
state = process.GetState()
assert state == lldb.eStateStopped
thread: SBThread = process.GetSelectedThread()
frame = thread.GetSelectedFrame()
assert frame.IsValid()
assert thread.IsValid()
frames:list[SBFrame] = thread.frames
frames = [frame for frame in frames]
frames.reverse()
current_frame = frames[-1]
previous_frame = frames[-2]
assert current_frame.IsValid()
print(f"Frame: {current_frame}")
print(f"Function: {current_frame.GetFunctionName()}")
calling_line_number = previous_frame.GetLineEntry().GetLine()
print(f"calling_line_number: {calling_line_number}")
line = main_file.read_text().split("\n")[calling_line_number - 1]
print(f"calling_line_number: {line}")
assert function_name_breakpoint in line, "<function name> not found in line, Why doesn't the line number match?"
vars = current_frame.GetVariables(True, True, True, True)
arg = [arg for arg in current_frame.arguments][0]
print(f"Arguments: {arg}")
struct = arg.Dereference()
print(f"Dereferenced: {struct}")
data = struct.GetChildAtIndex(0, lldb.eNoDynamicValues, True)
print(data)
hello = data.GetChildAtIndex(0, lldb.eNoDynamicValues, True)
world = data.GetChildAtIndex(1, lldb.eNoDynamicValues, True)
print(f"Hello: {hello}")
print(f"World: {world}")
length = struct.GetChildAtIndex(1, lldb.eNoDynamicValues, True)
print(f"Length: {length}")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment