Author: jdevlieghere Date: Thu May 9 15:14:14 2019 New Revision: 360386 URL: http://llvm.org/viewvc/llvm-project?rev=360386&view=rev Log: [Docs] Port python reference page
I somehow forgot to port over this page from the old website. Thank you Jim for the heads up! Added: lldb/trunk/docs/use/python-reference.rst Modified: lldb/trunk/docs/index.rst Modified: lldb/trunk/docs/index.rst URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/docs/index.rst?rev=360386&r1=360385&r2=360386&view=diff ============================================================================== --- lldb/trunk/docs/index.rst (original) +++ lldb/trunk/docs/index.rst Thu May 9 15:14:14 2019 @@ -40,6 +40,7 @@ Use & Extension use/symbolication use/symbols use/python + use/python-reference use/remote use/troubleshooting use/architecture Added: lldb/trunk/docs/use/python-reference.rst URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/docs/use/python-reference.rst?rev=360386&view=auto ============================================================================== --- lldb/trunk/docs/use/python-reference.rst (added) +++ lldb/trunk/docs/use/python-reference.rst Thu May 9 15:14:14 2019 @@ -0,0 +1,822 @@ +Python Reference +================ + +The entire LLDB API is available as Python functions through a script bridging +interface. This means the LLDB API's can be used directly from python either +interactively or to build python apps that provide debugger features. + +Additionally, Python can be used as a programmatic interface within the lldb +command interpreter (we refer to this for brevity as the embedded interpreter). +Of course, in this context it has full access to the LLDB API - with some +additional conveniences we will call out in the FAQ. + +.. contents:: + :local: + +Documentation +-------------- + +The LLDB API is contained in a python module named lldb. A useful resource when +writing Python extensions is the lldb Python classes reference guide. + +The documentation is also accessible in an interactive debugger session with +the following command: + +:: + + (lldb) script help(lldb) + Help on package lldb: + + NAME + lldb - The lldb module contains the public APIs for Python binding. + + FILE + /System/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/Python/lldb/__init__.py + + DESCRIPTION + ... + +You can also get help using a module class name. The full API that is exposed +for that class will be displayed in a man page style window. Below we want to +get help on the lldb.SBFrame class: + +:: + + (lldb) script help(lldb.SBFrame) + Help on class SBFrame in module lldb: + + class SBFrame(__builtin__.object) + | Represents one of the stack frames associated with a thread. + | SBThread contains SBFrame(s). For example (from test/lldbutil.py), + | + | def print_stacktrace(thread, string_buffer = False): + | '''Prints a simple stack trace of this thread.''' + | + ... + +Or you can get help using any python object, here we use the lldb.process +object which is a global variable in the lldb module which represents the +currently selected process: + +:: + + (lldb) script help(lldb.process) + Help on SBProcess in module lldb object: + + class SBProcess(__builtin__.object) + | Represents the process associated with the target program. + | + | SBProcess supports thread iteration. For example (from test/lldbutil.py), + | + | # ================================================== + | # Utility functions related to Threads and Processes + | # ================================================== + | + ... + +Embedded Python Interpreter +--------------------------- + +The embedded python interpreter can be accessed in a variety of ways from +within LLDB. The easiest way is to use the lldb command script with no +arguments at the lldb command prompt: + +:: + + (lldb) script + Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D. + >>> 2+3 + 5 + >>> hex(12345) + '0x3039' + >>> + +This drops you into the embedded python interpreter. When running under the +script command, lldb sets some convenience variables that give you quick access +to the currently selected entities that characterize the program and debugger +state. In each case, if there is no currently selected entity of the +appropriate type, the variable's IsValid method will return false. These +variables are: + ++-------------------+---------------------+-------------------------------------------------------------------------------------------------+ +| Variable | Type | Description | ++-------------------+---------------------+-------------------------------------------------------------------------------------------------+ +| **lldb.debugger** | **lldb.SBDebugger** | Contains the debugger object whose **script** command was invoked. | +| | | The **lldb.SBDebugger** object owns the command interpreter | +| | | and all the targets in your debug session. There will always be a | +| | | Debugger in the embedded interpreter. | ++-------------------+---------------------+-------------------------------------------------------------------------------------------------+ +| **lldb.target** | **lldb.SBTarget** | Contains the currently selected target - for instance the one made with the | +| | | **file** or selected by the **target select <target-index>** command. | +| | | The **lldb.SBTarget** manages one running process, and all the executable | +| | | and debug files for the process. | ++-------------------+---------------------+-------------------------------------------------------------------------------------------------+ +| **lldb.process** | **lldb.SBProcess** | Contains the process of the currently selected target. | +| | | The **lldb.SBProcess** object manages the threads and allows access to | +| | | memory for the process. | ++-------------------+---------------------+-------------------------------------------------------------------------------------------------+ +| **lldb.thread** | **lldb.SBThread** | Contains the currently selected thread. | +| | | The **lldb.SBThread** object manages the stack frames in that thread. | +| | | A thread is always selected in the command interpreter when a target stops. | +| | | The **thread select <thread-index>** command can be used to change the | +| | | currently selected thread. So as long as you have a stopped process, there will be | +| | | some selected thread. | ++-------------------+---------------------+-------------------------------------------------------------------------------------------------+ +| **lldb.frame** | **lldb.SBFrame** | Contains the currently selected stack frame. | +| | | The **lldb.SBFrame** object manage the stack locals and the register set for | +| | | that stack. | +| | | A stack frame is always selected in the command interpreter when a target stops. | +| | | The **frame select <frame-index>** command can be used to change the | +| | | currently selected frame. So as long as you have a stopped process, there will | +| | | be some selected frame. | ++-------------------+---------------------+-------------------------------------------------------------------------------------------------+ + + +While extremely convenient, these variables have a couple caveats that you +should be aware of. First of all, they hold the values of the selected objects +on entry to the embedded interpreter. They do not update as you use the LLDB +API's to change, for example, the currently selected stack frame or thread. + +Moreover, they are only defined and meaningful while in the interactive Python +interpreter. There is no guarantee on their value in any other situation, hence +you should not use them when defining Python formatters, breakpoint scripts and +commands (or any other Python extension point that LLDB provides). As a +rationale for such behavior, consider that lldb can run in a multithreaded +environment, and another thread might call the "script" command, changing the +value out from under you. + +To get started with these objects and LLDB scripting, please note that almost +all of the lldb Python objects are able to briefly describe themselves when you +pass them to the Python print function: + +:: + + (lldb) script + Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D. + >>> print lldb.debugger + Debugger (instance: "debugger_1", id: 1) + >>> print lldb.target + a.out + >>> print lldb.process + SBProcess: pid = 59289, state = stopped, threads = 1, executable = a.out + >>> print lldb.thread + SBThread: tid = 0x1f03 + >>> print lldb.frame + frame #0: 0x0000000100000bb6 a.out main + 54 at main.c:16 + + +Running a python script when a breakpoint gets hit +-------------------------------------------------- + +One very powerful use of the lldb Python API is to have a python script run +when a breakpoint gets hit. Adding python scripts to breakpoints provides a way +to create complex breakpoint conditions and also allows for smart logging and +data gathering. + +When your process hits a breakpoint to which you have attached some python +code, the code is executed as the body of a function which takes three +arguments: + +:: + + def breakpoint_function_wrapper(frame, bp_loc, dict): + # Your code goes here + + ++------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Argument | Type | Description | ++------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **frame** | **lldb.SBFrame** | The current stack frame where the breakpoint got hit. | +| | | The object will always be valid. | +| | | This **frame** argument might *not* match the currently selected stack frame found in the **lldb** module global variable **lldb.frame**. | ++------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **bp_loc** | **lldb.SBBreakpointLocation** | The breakpoint location that just got hit. Breakpoints are represented by **lldb.SBBreakpoint** | +| | | objects. These breakpoint objects can have one or more locations. These locations | +| | | are represented by **lldb.SBBreakpointLocation** objects. | ++------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **dict** | **dict** | The python session dictionary as a standard python dictionary object. | ++------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ + +Optionally, a Python breakpoint command can return a value. Returning False +tells LLDB that you do not want to stop at the breakpoint. Any other return +value (including None or leaving out the return statement altogether) is akin +to telling LLDB to actually stop at the breakpoint. This can be useful in +situations where a breakpoint only needs to stop the process when certain +conditions are met, and you do not want to inspect the program state manually +at every stop and then continue. + +An example will show how simple it is to write some python code and attach it +to a breakpoint. The following example will allow you to track the order in +which the functions in a given shared library are first executed during one run +of your program. This is a simple method to gather an order file which can be +used to optimize function placement within a binary for execution locality. + +We do this by setting a regular expression breakpoint that will match every +function in the shared library. The regular expression '.' will match any +string that has at least one character in it, so we will use that. This will +result in one lldb.SBBreakpoint object that contains an +lldb.SBBreakpointLocation object for each function. As the breakpoint gets hit, +we use a counter to track the order in which the function at this particular +breakpoint location got hit. Since our code is passed the location that was +hit, we can get the name of the function from the location, disable the +location so we won't count this function again; then log some info and continue +the process. + +Note we also have to initialize our counter, which we do with the simple +one-line version of the script command. + +Here is the code: + +:: + + (lldb) breakpoint set --func-regex=. --shlib=libfoo.dylib + Breakpoint created: 1: regex = '.', module = libfoo.dylib, locations = 223 + (lldb) script counter = 0 + (lldb) breakpoint command add --script-type python 1 + Enter your Python command(s). Type 'DONE' to end. + > # Increment our counter. Since we are in a function, this must be a global python variable + > global counter + > counter += 1 + > # Get the name of the function + > name = frame.GetFunctionName() + > # Print the order and the function name + > print '[%i] %s' % (counter, name) + > # Disable the current breakpoint location so it doesn't get hit again + > bp_loc.SetEnabled(False) + > # No need to stop here + > return False + > DONE + +The breakpoint command add command above attaches a python script to breakpoint 1. To remove the breakpoint command: + +:: + + (lldb) breakpoint command delete 1 + + +Using the python api's to create custom breakpoints +--------------------------------------------------- + + +Another use of the Python API's in lldb is to create a custom breakpoint +resolver. This facility was added in r342259. + +It allows you to provide the algorithm which will be used in the breakpoint's +search of the space of the code in a given Target to determine where to set the +breakpoint locations - the actual places where the breakpoint will trigger. To +understand how this works you need to know a little about how lldb handles +breakpoints. + +In lldb, a breakpoint is composed of three parts: the Searcher, the Resolver, +and the Stop Options. The Searcher and Resolver cooperate to determine how +breakpoint locations are set and differ between each breakpoint type. Stop +options determine what happens when a location triggers and includes the +commands, conditions, ignore counts, etc. Stop options are common between all +breakpoint types, so for our purposes only the Searcher and Resolver are +relevant. + +The Searcher's job is to traverse in a structured way the code in the current +target. It proceeds from the Target, to search all the Modules in the Target, +in each Module it can recurse into the Compile Units in that module, and within +each Compile Unit it can recurse over the Functions it contains. + +The Searcher can be provided with a SearchFilter that it will use to restrict +this search. For instance, if the SearchFilter specifies a list of Modules, the +Searcher will not recurse into Modules that aren't on the list. When you pass +the -s modulename flag to break set you are creating a Module-based search +filter. When you pass -f filename.c to break set -n you are creating a file +based search filter. If neither of these is specified, the breakpoint will have +a no-op search filter, so all parts of the program are searched and all +locations accepted. + +The Resolver has two functions. The most important one is the callback it +provides. This will get called at the appropriate time in the course of the +search. The callback is where the job of adding locations to the breakpoint +gets done. + +The other function is specifying to the Searcher at what depth in the above +described recursion it wants to be called. Setting a search depth also provides +a stop for the recursion. For instance, if you request a Module depth search, +then the callback will be called for each Module as it gets added to the +Target, but the searcher will not recurse into the Compile Units in the module. + +One other slight sublety is that the depth at which you get called back is not +necessarily the depth at which the the SearchFilter is specified. For instance, +if you are doing symbol searches, it is convenient to use the Module depth for +the search, since symbols are stored in the module. But the SearchFilter might +specify some subset of CompileUnits, so not all the symbols you might find in +each module will pass the search. You don't need to handle this situation +yourself, since SBBreakpoint::AddLocation will only add locations that pass the +Search Filter. This API returns an SBError to inform you whether your location +was added. + +When the breakpoint is originally created, its Searcher will process all the +currently loaded modules. The Searcher will also visit any new modules as they +are added to the target. This happens, for instance, when a new shared library +gets added to the target in the course of running, or on rerunning if any of +the currently loaded modules have been changed. Note, in the latter case, all +the locations set in the old module will get deleted and you will be asked to +recreate them in the new version of the module when your callback gets called +with that module. For this reason, you shouldn't try to manage the locations +you add to the breakpoint yourself. Note that the Breakpoint takes care of +deduplicating equal addresses in AddLocation, so you shouldn't need to worry +about that anyway. + +At present, when adding a scripted Breakpoint type, you can only provide a +custom Resolver, not a custom SearchFilter. + +The custom Resolver is provided as a Python class with the following methods: + ++--------------------+---------------------------------------+---------------------------------------------------------------------------------------------------------------------------------+ +| Name | Arguments | Description | ++--------------------+---------------------------------------+---------------------------------------------------------------------------------------------------------------------------------+ +| **__init__** | **bkpt: lldb.SBBreakpoint** | This is the constructor for the new Resolver. | +| | **extra_args: lldb.SBStructuredData** | | +| | | | +| | | **bkpt** is the breakpoint owning this Resolver. | +| | | | +| | | | +| | | **extra_args** is an SBStructuredData object that the user can pass in when creating instances of this | +| | | breakpoint. It is not required, but is quite handy. For instance if you were implementing a breakpoint on some | +| | | symbol name, you could write a generic symbol name based Resolver, and then allow the user to pass | +| | | in the particular symbol in the extra_args | ++--------------------+---------------------------------------+---------------------------------------------------------------------------------------------------------------------------------+ +| **__callback__** | **sym_ctx: lldb.SBSymbolContext** | This is the Resolver callback. | +| | | The **sym_ctx** argument will be filled with the current stage | +| | | of the search. | +| | | | +| | | | +| | | For instance, if you asked for a search depth of lldb.eSearchDepthCompUnit, then the | +| | | target, module and compile_unit fields of the sym_ctx will be filled. The callback should look just in the | +| | | context passed in **sym_ctx** for new locations. If the callback finds an address of interest, it | +| | | can add it to the breakpoint with the **SBBreakpoint::AddLocation** method, using the breakpoint passed | +| | | in to the **__init__** method. | ++--------------------+---------------------------------------+---------------------------------------------------------------------------------------------------------------------------------+ +| **__get_depth__** | **None** | Specify the depth at which you wish your callback to get called. The currently supported options are: | +| | | | +| | | lldb.eSearchDepthModule | +| | | lldb.eSearchDepthCompUnit | +| | | lldb.eSearchDepthFunction | +| | | | +| | | For instance, if you are looking | +| | | up symbols, which are stored at the Module level, you will want to get called back module by module. | +| | | So you would want to return **lldb.eSearchDepthModule**. This method is optional. If not provided the search | +| | | will be done at Module depth. | ++--------------------+---------------------------------------+---------------------------------------------------------------------------------------------------------------------------------+ +| **get_short_help** | **None** | This is an optional method. If provided, the returned string will be printed at the beginning of | +| | | the description for this breakpoint. | ++--------------------+---------------------------------------+---------------------------------------------------------------------------------------------------------------------------------+ + +To define a new breakpoint command defined by this class from the lldb command +line, use the command: + +:: + + (lldb) breakpoint set -P MyModule.MyResolverClass + +You can also populate the extra_args SBStructuredData with a dictionary of +key/value pairs with: + +:: + + (lldb) breakpoint set -P MyModule.MyResolverClass -k key_1 -v value_1 -k key_2 -v value_2 + +Although you can't write a scripted SearchFilter, both the command line and the +SB API's for adding a scripted resolver allow you to specify a SearchFilter +restricted to certain modules or certain compile units. When using the command +line to create the resolver, you can specify a Module specific SearchFilter by +passing the -s ModuleName option - which can be specified multiple times. You +can also specify a SearchFilter restricted to certain compile units by passing +in the -f CompUnitName option. This can also be specified more than once. And +you can mix the two to specify "this comp unit in this module". So, for +instance, + +:: + + (lldb) breakpoint set -P MyModule.MyResolverClass -s a.out + +will use your resolver, but will only recurse into or accept new locations in +the module a.out. + +Another option for creating scripted breakpoints is to use the +SBTarget.CreateBreakpointFromScript API. This one has the advantage that you +can pass in an arbitrary SBStructuredData object, so you can create more +complex parametrizations. SBStructuredData has a handy SetFromJSON method which +you can use for this purpose. Your __init__ function gets passed this +SBStructuredData object. This API also allows you to directly provide the list +of Modules and the list of CompileUnits that will make up the SearchFilter. If +you pass in empty lists, the breakpoint will use the default "search +everywhere,accept everything" filter. + +Using the python API' to create custom stepping logic +----------------------------------------------------- + +A slightly esoteric use of the Python API's is to construct custom stepping +types. LLDB's stepping is driven by a stack of "thread plans" and a fairly +simple state machine that runs the plans. You can create a Python class that +works as a thread plan, and responds to the requests the state machine makes to +run its operations. + +There is a longer discussion of scripted thread plans and the state machine, +and several interesting examples of their use in: + +https://github.com/llvm/llvm-project/blob/master/lldb/examples/python/scripted_step.py + +And for a MUCH fuller discussion of the whole state machine, see: + +https://github.com/llvm/llvm-project/blob/master/lldb/include/lldb/Target/ThreadPlan.h + +If you are reading those comments it is useful to know that scripted thread +plans are set to be "MasterPlans", and not "OkayToDiscard". + +To implement a scripted step, you define a python class that has the following +methods: + ++-------------------+------------------------------------+---------------------------------------------------------------------------------------+ +| Name | Arguments | Description | ++-------------------+------------------------------------+---------------------------------------------------------------------------------------+ +| **__init__** | **thread_plan: lldb.SBThreadPlan** | This is the underlying SBThreadPlan that is pushed onto the plan stack. | +| | | You will want to store this away in an ivar. Also, if you are going to | +| | | use one of the canned thread plans, you can queue it at this point. | ++-------------------+------------------------------------+---------------------------------------------------------------------------------------+ +| **explains_stop** | **event: lldb.SBEvent** | Return True if this stop is part of your thread plans logic, false otherwise. | ++-------------------+------------------------------------+---------------------------------------------------------------------------------------+ +| **is_stale** | **None** | If your plan is no longer relevant (for instance, you were | +| | | stepping in a particular stack frame, but some other operation | +| | | pushed that frame off the stack) return True and your plan will | +| | | get popped. | ++-------------------+------------------------------------+---------------------------------------------------------------------------------------+ +| **should_step** | **None** | Return True if you want lldb to instruction step one instruction, | +| | | or False to continue till the next breakpoint is hit. | ++-------------------+------------------------------------+---------------------------------------------------------------------------------------+ +| **should_stop** | **event: lldb.SBEvent** | If your plan wants to stop and return control to the user at this point, return True. | +| | | If your plan is done at this point, call SetPlanComplete on your | +| | | thread plan instance. | +| | | Also, do any work you need here to set up the next stage of stepping. | ++-------------------+------------------------------------+---------------------------------------------------------------------------------------+ + +To use this class to implement a step, use the command: + +:: + + (lldb) thread step-scripted -C MyModule.MyStepPlanClass + +Or use the SBThread.StepUsingScriptedThreadPlan API. The SBThreadPlan passed +into your __init__ function can also push several common plans (step +in/out/over and run-to-address) in front of itself on the stack, which can be +used to compose more complex stepping operations. When you use subsidiary plans +your explains_stop and should_stop methods won't get called until the +subsidiary plan is done, or the process stops for an event the subsidiary plan +doesn't explain. For instance, step over plans don't explain a breakpoint hit +while performing the step-over. + + +Create a new lldb command using a Python function +------------------------------------------------- + +Python functions can be used to create new LLDB command interpreter commands, +which will work like all the natively defined lldb commands. This provides a +very flexible and easy way to extend LLDB to meet your debugging requirements. + +To write a python function that implements a new LLDB command define the +function to take four arguments as follows: + +:: + + def command_function(debugger, command, result, internal_dict): + # Your code goes here + +Optionally, you can also provide a Python docstring, and LLDB will use it when providing help for your command, as in: + +:: + + def command_function(debugger, command, result, internal_dict): + """This command takes a lot of options and does many fancy things""" + # Your code goes here + +Starting with SVN revision 218834, LLDB Python commands can also take an +SBExecutionContext as an argument. This is useful in cases where the command's +notion of where to act is independent of the currently-selected entities in the +debugger. + +This feature is enabled if the command-implementing function can be recognized +as taking 5 arguments, or a variable number of arguments, and it alters the +signature as such: + +:: + + def command_function(debugger, command, exe_ctx, result, internal_dict): + # Your code goes here + ++-------------------+--------------------------------+----------------------------------------------------------------------------------------------------------------------------------+ +| Argument | Type | Description | ++-------------------+--------------------------------+----------------------------------------------------------------------------------------------------------------------------------+ +| **debugger** | **lldb.SBDebugger** | The current debugger object. | ++-------------------+--------------------------------+----------------------------------------------------------------------------------------------------------------------------------+ +| **command** | **python string** | A python string containing all arguments for your command. If you need to chop up the arguments | +| | | try using the **shlex** module's shlex.split(command) to properly extract the | +| | | arguments. | ++-------------------+--------------------------------+----------------------------------------------------------------------------------------------------------------------------------+ +| **exe_ctx** | **lldb.SBExecutionContext** | An execution context object carrying around information on the inferior process' context in which the command is expected to act | +| | | | +| | | *Optional since SVN r218834, unavailable before* | ++-------------------+--------------------------------+----------------------------------------------------------------------------------------------------------------------------------+ +| **result** | **lldb.SBCommandReturnObject** | A return object which encapsulates success/failure information for the command and output text | +| | | that needs to be printed as a result of the command. The plain Python "print" command also works but | +| | | text won't go in the result by default (it is useful as a temporary logging facility). | ++-------------------+--------------------------------+----------------------------------------------------------------------------------------------------------------------------------+ +| **internal_dict** | **python dict object** | The dictionary for the current embedded script session which contains all variables | +| | | and functions. | ++-------------------+--------------------------------+----------------------------------------------------------------------------------------------------------------------------------+ + +Starting with SVN revision 232224, Python commands can also be implemented by +means of a class which should implement the following interface: + +:: + + class CommandObjectType: + def __init__(self, debugger, session_dict): + this call should initialize the command with respect to the command interpreter for the passed-in debugger + def __call__(self, debugger, command, exe_ctx, result): + this is the actual bulk of the command, akin to Python command functions + def get_short_help(self): + this call should return the short help text for this command[1] + def get_long_help(self): + this call should return the long help text for this command[1] + +[1] This method is optional. + +As a convenience, you can treat the result object as a Python file object, and +say + +:: + + print >>result, "my command does lots of cool stuff" + +SBCommandReturnObject and SBStream both support this file-like behavior by +providing write() and flush() calls at the Python layer. + +One other handy convenience when defining lldb command-line commands is the +command command script import which will import a module specified by file +path, so you don't have to change your PYTHONPATH for temporary scripts. It +also has another convenience that if your new script module has a function of +the form: + +:: + + def __lldb_init_module(debugger, internal_dict): + # Command Initialization code goes here + +where debugger and internal_dict are as above, that function will get run when +the module is loaded allowing you to add whatever commands you want into the +current debugger. Note that this function will only be run when using the LLDB +command command script import, it will not get run if anyone imports your +module from another module. If you want to always run code when your module is +loaded from LLDB or when loaded via an import statement in python code you can +test the lldb.debugger object, since you imported the module at the top of the +python ls.py module. This test must be in code that isn't contained inside of +any function or class, just like the standard test for __main__ like all python +modules usually do. Sample code would look like: + +:: + + if __name__ == '__main__': + # Create a new debugger instance in your module if your module + # can be run from the command line. When we run a script from + # the command line, we won't have any debugger object in + # lldb.debugger, so we can just create it if it will be needed + lldb.debugger = lldb.SBDebugger.Create() + elif lldb.debugger: + # Module is being run inside the LLDB interpreter + lldb.debugger.HandleCommand('command script add -f ls.ls ls') + print 'The "ls" python command has been installed and is ready for use.' + +Now we can create a module called ls.py in the file ~/ls.py that will implement +a function that can be used by LLDB's python command code: + +:: + + #!/usr/bin/python + + import lldb + import commands + import optparse + import shlex + + def ls(debugger, command, result, internal_dict): + print >>result, (commands.getoutput('/bin/ls %s' % command)) + + # And the initialization code to add your commands + def __lldb_init_module(debugger, internal_dict): + debugger.HandleCommand('command script add -f ls.ls ls') + print 'The "ls" python command has been installed and is ready for use.' + +Now we can load the module into LLDB and use it + +:: + + % lldb + (lldb) command script import ~/ls.py + The "ls" python command has been installed and is ready for use. + (lldb) ls -l /tmp/ + total 365848 + -rw-r--r--@ 1 someuser wheel 6148 Jan 19 17:27 .DS_Store + -rw------- 1 someuser wheel 7331 Jan 19 15:37 crash.log + +A more interesting template has been created in the source repository that can +help you to create lldb command quickly: + +https://github.com/llvm/llvm-project/blob/master/lldb/examples/python/cmdtemplate.py + +A commonly required facility is being able to create a command that does some +token substitution, and then runs a different debugger command (usually, it +po'es the result of an expression evaluated on its argument). For instance, +given the following program: + +:: + + #import <Foundation/Foundation.h> + NSString* + ModifyString(NSString* src) + { + return [src stringByAppendingString:@"foobar"]; + } + + int main() + { + NSString* aString = @"Hello world"; + NSString* anotherString = @"Let's be friends"; + return 1; + } + +you may want a pofoo X command, that equates po [ModifyString(X) +capitalizedString]. The following debugger interaction shows how to achieve +that goal: + +:: + + (lldb) script + Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D. + >>> def pofoo_funct(debugger, command, result, internal_dict): + ... cmd = "po [ModifyString(" + command + ") capitalizedString]" + ... lldb.debugger.HandleCommand(cmd) + ... + >>> ^D + (lldb) command script add pofoo -f pofoo_funct + (lldb) pofoo aString + $1 = 0x000000010010aa00 Hello Worldfoobar + (lldb) pofoo anotherString + $2 = 0x000000010010aba0 Let's Be Friendsfoobar + +Using the lldb.py module in Python +---------------------------------- + +LLDB has all of its core code build into a shared library which gets used by +the lldb command line application. On Mac OS X this shared library is a +framework: LLDB.framework and on other unix variants the program is a shared +library: lldb.so. LLDB also provides an lldb.py module that contains the +bindings from LLDB into Python. To use the LLDB.framework to create your own +stand-alone python programs, you will need to tell python where to look in +order to find this module. This is done by setting the PYTHONPATH environment +variable, adding a path to the directory that contains the lldb.py python +module. The lldb driver program has an option to report the path to the lldb +module. You can use that to point to correct lldb.py: + +For csh and tcsh: + +:: + + % setenv PYTHONPATH `lldb -P` + +For sh and bash: + +:: + + % export PYTHONPATH=`lldb -P` + +Alternately, you can append the LLDB Python directory to the sys.path list +directly in your Python code before importing the lldb module. + +Now your python scripts are ready to import the lldb module. Below is a python +script that will launch a program from the current working directory called +"a.out", set a breakpoint at "main", and then run and hit the breakpoint, and +print the process, thread and frame objects if the process stopped: + +:: + + #!/usr/bin/python + + import lldb + import os + + def disassemble_instructions(insts): + for i in insts: + print i + + # Set the path to the executable to debug + exe = "./a.out" + + # Create a new debugger instance + debugger = lldb.SBDebugger.Create() + + # When we step or continue, don't return from the function until the process + # stops. Otherwise we would have to handle the process events ourselves which, while doable is + #a little tricky. We do this by setting the async mode to false. + debugger.SetAsync (False) + + # Create a target from a file and arch + print "Creating a target for '%s'" % exe + + target = debugger.CreateTargetWithFileAndArch (exe, lldb.LLDB_ARCH_DEFAULT) + + if target: + # If the target is valid set a breakpoint at main + main_bp = target.BreakpointCreateByName ("main", target.GetExecutable().GetFilename()); + + print main_bp + + # Launch the process. Since we specified synchronous mode, we won't return + # from this function until we hit the breakpoint at main + process = target.LaunchSimple (None, None, os.getcwd()) + + # Make sure the launch went ok + if process: + # Print some simple process info + state = process.GetState () + print process + if state == lldb.eStateStopped: + # Get the first thread + thread = process.GetThreadAtIndex (0) + if thread: + # Print some simple thread info + print thread + # Get the first frame + frame = thread.GetFrameAtIndex (0) + if frame: + # Print some simple frame info + print frame + function = frame.GetFunction() + # See if we have debug info (a function) + if function: + # We do have a function, print some info for the function + print function + # Now get all instructions for this function and print them + insts = function.GetInstructions(target) + disassemble_instructions (insts) + else: + # See if we have a symbol in the symbol table for where we stopped + symbol = frame.GetSymbol(); + if symbol: + # We do have a symbol, print some info for the symbol + print symbol + +Writing lldb frame recognizers in Python +---------------------------------------- + +Frame recognizers allow for retrieving information about special frames based +on ABI, arguments or other special properties of that frame, even without +source code or debug info. Currently, one use case is to extract function +arguments that would otherwise be unaccesible, or augment existing arguments. + +Adding a custom frame recognizer is done by implementing a Python class and +using the 'frame recognizer add' command. The Python class should have a +'get_recognized_arguments' method and it will receive an argument of type +lldb.SBFrame representing the current frame that we are trying to recognize. +The method should return a (possibly empty) list of lldb.SBValue objects that +represent the recognized arguments. + +An example of a recognizer that retrieves the file descriptor values from libc +functions 'read', 'write' and 'close' follows: + +:: + + class LibcFdRecognizer(object): + def get_recognized_arguments(self, frame): + if frame.name in ["read", "write", "close"]: + fd = frame.EvaluateExpression("$arg1").unsigned + value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd) + return [value] + return [] + +The file containing this implementation can be imported via 'command script +import' and then we can register this recognizer with 'frame recognizer add'. +It's important to restrict the recognizer to the libc library (which is +libsystem_kernel.dylib on macOS) to avoid matching functions with the same name +in other modules: + +:: + + (lldb) command script import .../fd_recognizer.py + (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib + +When the program is stopped at the beginning of the 'read' function in libc, we can view the recognizer arguments in 'frame variable': + +:: + + (lldb) b read + (lldb) r + Process 1234 stopped + * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3 + frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read + (lldb) frame variable + (int) fd = 3 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits