Skip to content

Instantly share code, notes, and snippets.

@nkaretnikov
Last active September 21, 2019 17:06
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 nkaretnikov/6ee00afabf73332c5a89eacb610369c2 to your computer and use it in GitHub Desktop.
Save nkaretnikov/6ee00afabf73332c5a89eacb610369c2 to your computer and use it in GitHub Desktop.
lldb trace

Start debugserver.

tty0$ sudo debugserver localhost:8000 main

Run the script in lldb. Note that the second pc line is incorrect (pc: 0xffffffffffffffff).

tty1$ lldb --version
lldb version 10.0.0 (https://github.com/llvm/llvm-project.git revision a7e9059967c4bff83ae6c3b595828bbbc8aaf82e)
  clang revision a7e9059967c4bff83ae6c3b595828bbbc8aaf82e
  llvm revision a7e9059967c4bff83ae6c3b595828bbbc8aaf82e

tty1$ lldb
(lldb) command script import trace.py
Process 27331 stopped
* thread #1, stop reason = signal SIGSTOP
    frame #0: 0x000000010d978000 dyld`_dyld_start
dyld`_dyld_start:
->  0x10d978000 <+0>: pop    rdi
    0x10d978001 <+1>: push   0x0
    0x10d978003 <+3>: mov    rbp, rsp
    0x10d978006 <+6>: and    rsp, -0x10
(lldb) pc: 0x105514f50
pc: 0xffffffffffffffff
Assertion failed: (!m_plan_stack.empty()), function PushPlan, file /Users/nikita/llvm/lldb/source/Target/Thread.cpp, line 1017.
0  lldb                     0x000000010f2d3375 llvm::sys::PrintStackTrace(llvm::raw_ostream&) + 37
1  lldb                     0x000000010f2d2877 llvm::sys::RunSignalHandlers() + 39
2  lldb                     0x000000010f2d39e8 SignalHandler(int) + 264
3  libsystem_platform.dylib 0x00007fff7a7ffb5d _sigtramp + 29
4  libsystem_platform.dylib 0x0000000000000001 _sigtramp + 18446603338460955841
5  libsystem_c.dylib        0x00007fff7a6b96a6 abort + 127
6  libsystem_c.dylib        0x00007fff7a68220d basename_r + 0
7  LLDB                     0x0000000111184c2c lldb_private::Thread::PushPlan(std::__1::shared_ptr<lldb_private::ThreadPlan>&) + 460
8  LLDB                     0x0000000111182ff7 lldb_private::Thread::QueueThreadPlan(std::__1::shared_ptr<lldb_private::ThreadPlan>&, bool) + 167
9  LLDB                     0x0000000111185303 lldb_private::Thread::QueueThreadPlanForStepSingleInstruction(bool, bool, bool, lldb_private::Status&) + 259
10 LLDB                     0x0000000110e5562a lldb::SBThread::StepInstruction(bool, lldb::SBError&) + 538
11 LLDB                     0x0000000110e55221 lldb::SBThread::StepInstruction(bool) + 177
12 LLDB                     0x0000000110f69e1c _wrap_SBThread_StepInstruction(_object*, _object*) + 268
13 Python                   0x00007fff58632191 PyEval_EvalFrameEx + 1198
14 Python                   0x00007fff58631ab2 PyEval_EvalCodeEx + 1555
15 Python                   0x00007fff58637d4c _PyEval_SliceIndex + 490
16 Python                   0x00007fff58632498 PyEval_EvalFrameEx + 1973
17 Python                   0x00007fff58637cee _PyEval_SliceIndex + 396
18 Python                   0x00007fff58632498 PyEval_EvalFrameEx + 1973
19 Python                   0x00007fff58631ab2 PyEval_EvalCodeEx + 1555
20 Python                   0x00007fff585d92ea PyFunction_SetClosure + 779
21 Python                   0x00007fff585bc078 PyObject_Call + 97
22 Python                   0x00007fff58637710 PyEval_CallObjectWithKeywords + 159
23 LLDB                     0x000000011140e8e4 lldb_private::PythonCallable::operator()(std::initializer_list<lldb_private::PythonObject>) + 52
24 LLDB                     0x0000000110edcd5f lldb_private::PythonObject lldb_private::PythonCallable::operator()<lldb_private::PythonObject, lldb_private::PythonObject, lldb_private::PythonDictionary>(lldb_private::PythonObject const&, lldb_private::PythonObject, lldb_private::PythonDictionary) + 287
25 LLDB                     0x0000000110edcaa8 LLDBSwigPythonBreakpointCallbackFunction + 728
26 LLDB                     0x0000000111411b93 lldb_private::ScriptInterpreterPythonImpl::BreakpointCallbackFunction(void*, lldb_private::StoppointCallbackContext*, unsigned long long, unsigned long long) + 371
27 LLDB                     0x0000000111164efe lldb_private::StopInfoBreakpoint::PerformAction(lldb_private::Event*) + 2830
28 LLDB                     0x0000000111146089 lldb_private::Process::ProcessEventData::DoOnRemoval(lldb_private::Event*) + 809
29 LLDB                     0x00000001111b6b0a lldb_private::Listener::FindNextEventInternal(std::__1::unique_lock<std::__1::mutex>&, lldb_private::Broadcaster*, lldb_private::ConstString const*, unsigned int, unsigned int, std::__1::shared_ptr<lldb_private::Event>&, bool) + 570
30 LLDB                     0x00000001111b6eb0 lldb_private::Listener::GetEventInternal(lldb_private::Timeout<std::__1::ratio<1l, 1000000l> > const&, lldb_private::Broadcaster*, lldb_private::ConstString const*, unsigned int, unsigned int, std::__1::shared_ptr<lldb_private::Event>&) + 352
31 LLDB                     0x00000001111b7081 lldb_private::Listener::GetEvent(std::__1::shared_ptr<lldb_private::Event>&, lldb_private::Timeout<std::__1::ratio<1l, 1000000l> > const&) + 33
32 LLDB                     0x0000000110fbff9e lldb_private::Debugger::DefaultEventHandler() + 302
33 LLDB                     0x0000000110fc0299 lldb_private::Debugger::EventHandlerThread(void*) + 9
34 LLDB                     0x000000011106545a lldb_private::HostNativeThreadBase::ThreadCreateTrampoline(void*) + 106
35 libsystem_pthread.dylib  0x00007fff7a8082eb _pthread_body + 126
36 libsystem_pthread.dylib  0x00007fff7a80b249 _pthread_start + 66
37 libsystem_pthread.dylib  0x00007fff7a80740d thread_start + 13
zsh: abort
// gcc -Wall -Werror -Wextra -g -o main main.c
#include <stdio.h>
int main()
{
printf("Hello, world!\n");
return 0;
}
# command script import scripted_step.py
from __future__ import print_function
import lldb
import sys
TARGET = None
START_ADDR = None
INVALID_ADDR = 0xffffffffffffffff
def log(s):
sys.stdout.write(s)
sys.stdout.flush()
def run(cmd):
res = lldb.SBCommandReturnObject()
lldb.debugger.GetCommandInterpreter().HandleCommand(cmd, res)
return res.GetOutput()
def function_address(fname):
global TARGET
# XXX: Multiple functions are not supported.
funcs = list(TARGET.FindFunctions(fname))
for i in range(len(funcs)):
# XXX: Is this a good way to filter out inlined functions?
if funcs[i].GetSymbol().GetType() != 2:
del funcs[i]
assert len(funcs) == 1
return funcs[0].GetFunction().GetStartAddress()
def trace(frame, _bp_loc, _dict):
log('trace\n')
global TARGET
process = TARGET.GetProcess()
thread = process.GetSelectedThread()
resume_immediately = True
# resume_immediately = False
thread.StepUsingScriptedThreadPlan(SimpleStep.__name__, resume_immediately)
log('trace done\n')
return False # continue
class SimpleStep:
def __init__(self, thread_plan, dict_):
log('init\n')
global START_ADDR
assert START_ADDR != None
assert START_ADDR != INVALID_ADDR
self.thread_plan = thread_plan
# self.start_addr = thread_plan.GetThread().GetFrameAtIndex(0).GetPC()
self.start_addr = START_ADDR
self.end_addr = self.start_addr + 26 # ret
log('init done\n')
def explains_stop(self, event):
log('explains stop\n')
stop_reason = self.thread_plan.GetThread().GetStopReason()
# log('stop_reason: {}\n'.format(stop_reason))
if stop_reason == lldb.eStopReasonTrace:
log('explains stop done: True\n')
return True
else:
log('explains stop done: False\n')
return False
def should_stop(self, event):
log('should stop\n')
cur_pc = self.thread_plan.GetThread().GetFrameAtIndex(0).GetPC()
# if cur_pc < self.start_addr or cur_pc >= self.end_addr:
if cur_pc == self.end_addr:
self.thread_plan.SetPlanComplete(True)
log('should stop done: True\n')
return True
else:
# log('in range\n')
process = TARGET.GetProcess()
thread = process.GetSelectedThread()
frame = thread.GetSelectedFrame()
pc = frame.GetPCAddress()
func_name = pc.GetFunction().name
line_num = pc.GetLineEntry().line
insns = TARGET.ReadInstructions(pc, 1, 'intel')
insn = insns.GetInstructionAtIndex(0)
mnemonic = insn.mnemonic
operands = insn.operands
if func_name:
file_str = '{}; {}:{}'.format(' ' * 2, func_name, line_num)
else:
file_str = ''
log('0x{:08x}: {} {}{}\n'
.format(pc.load_addr, mnemonic, operands, file_str))
log('should stop done: False\n')
return False
def should_step(self):
log('should step\n')
return True
def main():
global TARGET
global START_ADDR
run('gdb-remote 8000')
debugger = lldb.debugger
debugger.SetAsync(True)
TARGET = debugger.GetSelectedTarget()
TARGET.DeleteAllBreakpoints()
TARGET.DeleteAllWatchpoints()
addr = function_address('main')
addr = addr.GetLoadAddress(TARGET)
assert addr != INVALID_ADDR
breakpoint = TARGET.BreakpointCreateByAddress(addr)
START_ADDR = addr
callback = '{}.{}'.format(__name__, trace.__name__)
breakpoint.SetScriptCallbackFunction(callback)
run('cont')
def __lldb_init_module(_debugger, _dict):
main()
# command script import trace.py
import lldb
import sys
TARGET = None
def log(s):
sys.stdout.write(s)
sys.stdout.flush()
def run(cmd):
res = lldb.SBCommandReturnObject()
lldb.debugger.GetCommandInterpreter().HandleCommand(cmd, res)
return res.GetOutput()
def function_address(fname):
global TARGET
# XXX: Multiple functions are not supported.
funcs = list(TARGET.FindFunctions(fname))
for i in range(len(funcs)):
# XXX: Is this a good way to filter out inlined functions?
if funcs[i].GetSymbol().GetType() != 2:
del funcs[i]
assert len(funcs) == 1
return funcs[0].GetFunction().GetStartAddress()
def trace(frame, _bp_loc, _dict):
global TARGET
process = TARGET.GetProcess()
thread = process.GetThreadAtIndex(0)
frame = thread.GetFrameAtIndex(0)
# thread = process.GetSelectedThread()
# frame = thread.GetSelectedFrame()
pc = frame.GetPCAddress()
# XXX: Debug.
i = 0
while i < 2:
log('pc: 0x{:08x}\n'.format(pc.GetLoadAddress(TARGET)))
thread.StepInstruction(False)
# frame = thread.GetSelectedFrame()
pc = frame.GetPCAddress()
i += 1
return False # continue
def main():
global TARGET
run('gdb-remote 8000')
TARGET = lldb.debugger.GetSelectedTarget()
TARGET.DeleteAllBreakpoints()
TARGET.DeleteAllWatchpoints()
addr = function_address('main')
addr = addr.GetLoadAddress(TARGET)
assert addr != 0xffffffffffffffff
breakpoint = TARGET.BreakpointCreateByAddress(addr)
callback = '{}.{}'.format(__name__, trace.__name__)
breakpoint.SetScriptCallbackFunction(callback)
run('cont')
def __lldb_init_module(_debugger, _dict):
main()
@nkaretnikov
Copy link
Author

ProductName: Mac OS X
ProductVersion: 10.14.6
BuildVersion: 18G87

(lldb was built from source yesterday.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment