| # Scripting Bridge API | |
| The SB APIs constitute the stable C++ API that lldb presents to external | |
| clients, and which get processed by SWIG to produce the Python bindings to | |
| lldb. As such it is important that they not suffer from the binary | |
| incompatibilities that C++ is so susceptible to. We've established a few rules | |
| to ensure that this happens. | |
| ## Extending the SB API | |
| The classes in the SB API's are all called SB\<SomeName>, where SomeName is in | |
| CamelCase starting with an upper case letter. The method names are all | |
| CamelCase with initial capital letter as well. | |
| All the SB API classes are non-virtual, single inheritance classes. They should | |
| only include SBDefines.h or other SB headers as needed. There should be no | |
| inlined method implementations in the header files, they should all be in the | |
| implementation files. And there should be no direct ivar access. | |
| You also need to choose the ivars for the class with care, since you can't add | |
| or remove ivars without breaking binary compatibility. In some cases, the SB | |
| class is a thin wrapper around an internal lldb_private object. In that case, | |
| the class can have a single ivar, which is either a pointer, shared_ptr or | |
| unique_ptr to the object in the lldb_private API. All the lldb_private classes | |
| that get used this way are declared as opaque classes in lldb-forward.h, which | |
| is included in SBDefines.h. So if you need an SB class to wrap an lldb_private | |
| class that isn't in lldb-forward.h, add it there rather than making a direct | |
| opaque declaration in the SB classes .h file. | |
| If the SB Class needs some state of its own, as well as the backing object, | |
| don't include that as a direct ivar in the SB Class. Instead, make an Impl | |
| class in the SB's .cpp file, and then make the SB object hold a shared or | |
| unique pointer to the Impl object. The theory behind this is that if you need | |
| more state in the SB object, those needs are likely to change over time, and | |
| this way the Impl class can pick up members without changing the size of the | |
| object. An example of this is the SBValue class. Please note that you should | |
| not put this Impl class in the lldb namespace. Failure to do so leads to | |
| leakage of weak-linked symbols in the SBAPI. | |
| In order to fit into the Python API's, we need to be able to default construct | |
| all the SB objects. Since the ivars of the classes are all pointers of one sort | |
| or other, this can easily be done, but it means all the methods must be | |
| prepared to handle their opaque implementation pointer being empty, and doing | |
| something reasonable. We also always have an "IsValid" method on all the SB | |
| classes to report whether the object is empty or not. | |
| :::{note} | |
| The implication of an object being "empty" can vary by class. | |
| For most classes, the lack of anything backing the class means that it | |
| would not be valid to interact with it by calling any other methods | |
| on it. | |
| One exception to this is `SBError`, which can provide valid | |
| information even when empty. This is because it does not need an | |
| underlying object to be able to represent a success state. | |
| ::: | |
| Another piece of the SB API infrastructure is the Python (or other script | |
| interpreter) customization. SWIG allows you to add property access, iterators | |
| and documentation to classes. We place the property accessors and iterators in | |
| a file dedicated to extensions to existing SB classes at | |
| "bindings/interface/SB\<ClassName>Extensions.i". The documentation is similarly | |
| located at "bindings/interface/SB\<ClassName>Docstrings.i". These two files, in | |
| addition to the actual header SB\<ClassName>.h, forms the interface that lldb | |
| exposes to users through the scripting languages. | |
| There are some situations where you may want to add functionality to the SB API | |
| only for use in C++. To prevent SWIG from generating bindings to these | |
| functions, you can use a C macro guard, like so: | |
| ``` | |
| #ifndef SWIG | |
| int GetResourceCPPOnly() const; | |
| #endif | |
| ``` | |
| In this case, `GetResourceCPPOnly` will not be generated for Python or other | |
| scripting languages. If you wanted to add a resource specifically only for the | |
| SWIG case, you can invert the condition and use `#ifdef SWIG` instead. When | |
| building the LLDB framework for macOS, the headers are processed with | |
| `unifdef` prior to being copied into the framework bundle to remove macros | |
| involving SWIG. | |
| Another good principle when adding SB API methods is: if you find yourself | |
| implementing a significant algorithm in the SB API method, you should not do | |
| that, but instead look for and then add it - if not found - as a method in the | |
| underlying lldb_private class, and then call that from your SB API method. | |
| If it was a useful algorithm, it's very likely it already exists | |
| because the lldb_private code also needed to do it. And if it doesn't at | |
| present, if it was a useful thing to do, it's likely someone will later need | |
| it in lldb_private and then we end up with two implementations of the same | |
| algorithm. If we keep the SB API code to just what's needed to manage the SB | |
| objects and requests, we won't get into this situation. | |
| ## Lifetime | |
| Many SB API methods will return strings in the form of `const char *` values. | |
| Once created, these strings are guaranteed to live until the end of the | |
| debugging session. LLDB owns these strings, clients should not attempt to free | |
| them. Doing so may cause LLDB to crash. | |
| Note that this only affects the C++ API as scripting languages usually | |
| will usually create native string types from the `const char *` value. | |
| ## API Instrumentation | |
| The reproducer infrastructure requires API methods to be instrumented so that | |
| they can be captured and replayed. Instrumentation consists of two macros, | |
| `LLDB_REGISTER` and `LLDB_RECORD`. Both can be automatically generated with | |
| the `lldb-instr` utility. | |
| To add instrumentation for a given file, pass it to the `lldb-instr` tool. | |
| Like other clang-based tools it requires a compilation database | |
| (`compile_commands.json`) to be present in the current working directory. | |
| ``` | |
| $ ./bin/lldb-instr /path/to/lldb/source/API/SBDebugger.cpp | |
| ``` | |
| The tool will automatically insert `LLDB_RECORD` macros inline, however you | |
| will need to run `clang-format` over the processed file, as the tool | |
| (intentionally) makes no attempt to get that right. | |
| The `LLDB_REGISTER` macros are printed to standard out between curly braces. | |
| You'll have to copy-paste those into the corresponding `RegisterMethods` | |
| function in the implementation file. This function is fully specialized in the | |
| corresponding type. | |
| ``` | |
| template <> void RegisterMethods<SBDebugger>(Registry &R) { | |
| ... | |
| } | |
| ``` | |
| When adding a new class, you'll also have to add a call to `RegisterMethods` | |
| in the `SBRegistry` constructor. | |
| The tool can be used incrementally. However, it will ignore existing macros | |
| even if their signature is wrong. It will only generate a `LLDB_REGISTER` if | |
| it emitted a corresponding `LLDB_RECORD` macro. |