{"id":17592,"date":"2019-11-26T08:30:36","date_gmt":"2019-11-26T07:30:36","guid":{"rendered":"https:\/\/www.inovex.de\/blog\/?p=17592"},"modified":"2022-11-21T16:11:52","modified_gmt":"2022-11-21T15:11:52","slug":"lldb-patch-your-code-with-breakpoints","status":"publish","type":"post","link":"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/","title":{"rendered":"LLDB: Patch Your Code with Breakpoints"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_79_2 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\"><p class=\"ez-toc-title\" style=\"cursor:inherit\"><\/p>\n<\/div><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#tldr\" >tl;dr<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Introduction\" >Introduction<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Breakpoints-in-Theory\" >Breakpoints in Theory<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Software-Breakpoint\" >Software Breakpoint<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Hardware-Breakpoint\" >Hardware Breakpoint<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Non-Symbolic-Breakpoint\" >Non-Symbolic Breakpoint<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Symbolic-Breakpoint\" >Symbolic Breakpoint<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Breakpoints-in-Practice\" >Breakpoints in Practice<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Create-a-Breakpoint\" >Create a Breakpoint<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Conditional-Breakpoint\" >Conditional Breakpoint<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#MetaBreakpoint-Breakpoints-Modifying-Breakpoints\" >MetaBreakpoint: Breakpoints Modifying Breakpoints<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Example-Usage-of-MetaBreakpoints\" >Example Usage of MetaBreakpoints<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#printf-like-Debugging\" >printf()-like Debugging<\/a><ul class='ez-toc-list-level-4' ><li class='ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#DRY-and-Commands\" >DRY and Commands<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-15\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Mute-AVPlayer-on-Initialisation\" >Mute AVPlayer on Initialisation<\/a><ul class='ez-toc-list-level-4' ><li class='ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-16\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Solution-1\" >Solution #1<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-17\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Solution-2\" >Solution #2<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-18\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Solution-3\" >Solution #3<\/a><\/li><\/ul><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-19\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Control-Flow-Manipulation\" >Control Flow Manipulation<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-20\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#thread-jump\" >thread jump<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-21\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#thread-return\" >thread return<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-22\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Binary-Patch-Breakpoints\" >Binary Patch Breakpoints<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-23\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Persisting-Breakpoints\" >Persisting Breakpoints<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-24\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Conclusion\" >Conclusion<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-25\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#Read-on\" >Read on<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"tldr\"><\/span>tl;dr<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Ever wanted to change some behaviour of your application during development without the need to recompile it? <a href=\"https:\/\/lldb.llvm.org\">LLDB<\/a>\u00a0has got you covered. This article explains how LLDB is used through its CLI, how simple breakpoints are created, and finally how they can be used to non-destructively alter current application behaviour.<!--more--><\/p>\n<h2><span class=\"ez-toc-section\" id=\"Introduction\"><\/span>Introduction<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The <a href=\"https:\/\/lldb.llvm.org\">LLDB<\/a> debugger is part of the <a href=\"https:\/\/llvm.org\">LLVM<\/a>\u00a0project and has been your debugger of choice since Xcode 6 if you develop for Apple&#8217;s ecosystem.<\/p>\n<p>On macOS it is part of <a href=\"https:\/\/developer.apple.com\/xcode\/\">Xcode<\/a> or installs itself by typing <em>lldb<\/em> into the command shell. On Debian-based Linux systems it can be installed via <a href=\"https:\/\/apt.llvm.org\"><em>apt get<\/em><\/a>, and for all other <a href=\"https:\/\/llvm.org\/docs\/GettingStarted.html#hardware\">systems<\/a> the recommended way is to\u00a0<a href=\"https:\/\/llvm.org\/docs\/CMake.html\">build it<\/a> from source via CMake.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Breakpoints-in-Theory\"><\/span>Breakpoints in Theory<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>As software developers we use a debugger and its most significant feature\u2014the breakpoint\u2014quite a lot, mostly unaware if the breakpoint that is currently used is a <em>symbolic<\/em>, <em>non-symbolic<\/em>, <em>hardware<\/em>, or <em>software<\/em> breakpoint.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Software-Breakpoint\"><\/span>Software Breakpoint<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><em>Software breakpoints<\/em>, as the name implies, are breakpoints within the binary that is being debugged. It works by replacing an existing <em>opcode<\/em> at the position the debugger should halt our program with an <em>opcode<\/em> that forces the CPU to emit a software interrupt (a.k.a.\u00a0<em>trap<\/em>). After the breakpoint is hit and the interrupt is sent, the debugger receives the interrupt signal, replaces the <em>opcode<\/em> with the original <em>opcode<\/em> and usually waits for the next command. This could be something like step to next instruction or continue program execution until next breakpoint is hit.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Hardware-Breakpoint\"><\/span>Hardware Breakpoint<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>A <em>hardware breakpoint<\/em>, you might have already guessed it, is a breakpoint that uses dedicated hardware, e.g. a\u00a0<a href=\"https:\/\/en.wikipedia.org\/wiki\/X86_debug_register\">x86 debug register<\/a>, to observe the current state of the CPU and halt program execution. Because it relies on dedicated hardware features, the number of hardware breakpoints that can be used is significantly lower (highly depends on the processor&#8217;s architecture, but generally less than a dozen) than the number of software breakpoints that can be used.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Non-Symbolic-Breakpoint\"><\/span>Non-Symbolic Breakpoint<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>A Non-Symbolic breakpoint is used by the IDE if a line of code is marked for the debugger to stop program execution. The location within the source code is translated into an execution address where the debugger actually places the breakpoint. Non-symbolic breakpoints stick to their specified location within the source code or binary and do not &#8222;move&#8220; with the instruction \/ source code. This characteristic makes it hard to use these kinds of breakpoints for automating tasks with LLDB.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Symbolic-Breakpoint\"><\/span>Symbolic Breakpoint<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Symbolic breakpoints, as opposed to non-symbolic breakpoints, do not stick to a line of code or a specific binary address. They are bound to a symbol, e.g. the name of a function. Which means that no matter where the function is located within the source code\u2014or even binary if it is a global symbol\u2014the breakpoint moves with it. A disadvantage of symbolic breakpoints is, that they cannot be easily placed in the middle or end of a function.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Breakpoints-in-Practice\"><\/span>Breakpoints in Practice<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Before we start to deep dive into LLDB and how breakpoints can be used to alter code execution, let&#8217;s take a step back and get familiar with the command line interface of LLDB as well as how breakpoints are created manually without the need of an IDE. After typing <code>lldb<\/code> into a shell a prompt should be visible like the one below.<\/p>\n<pre><code>$ (lldb)<\/code><\/pre>\n<h3><span class=\"ez-toc-section\" id=\"Create-a-Breakpoint\"><\/span>Create a Breakpoint<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>The following command creates an IDE-like non-symbolic breakpoint at <em>line 3<\/em> in file <em>main.c<\/em>.<\/p>\n<pre><code>$ (lldb) breakpoint set --file main.c --line 3<\/code><\/pre>\n<p>which can be abbreviated to<\/p>\n<pre><code>$ (lldb) br s -f main.c -l 3<\/code><\/pre>\n<p>because the CLI will understand our input as long as there is no ambiguity with other LLDB CLI commands. Up to now we are as good or bad as any common IDE might be in creating breakpoints.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Conditional-Breakpoint\"><\/span>Conditional Breakpoint<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Just creating a breakpoint might not always be enough in some, mostly hard to debug use cases. For example let&#8217;s assume a situation as described in the picture below. The green boxes represent the callers of <code>foo(char * value)<\/code> that do not trigger an assertion whereas the red box represents the caller that triggers the assertion which is the &#8222;bug&#8220;.<\/p>\n<figure><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-17600 size-full\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/conditions.png\" alt=\"2 files being called by a function\" width=\"495\" height=\"249\" srcset=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/conditions.png 495w, https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/conditions-300x151.png 300w, https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/conditions-400x201.png 400w, https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/conditions-360x181.png 360w\" sizes=\"auto, (max-width: 495px) 100vw, 495px\" \/><\/figure>\n<p>To debug the defect we could alter our source code e.g. by inserting something like<\/p>\n<pre><code class=\"c\">if (NULL == value) {\r\n\r\n    printf(\"Make a breakpoint here\");\r\n\r\n}<\/code><\/pre>\n<p>at the beginning of <code>foo(char * value)<\/code> and add a breakpoint to the <code>printf()<\/code> statement. This is something I personally try to prevent at any cost, because<\/p>\n<ul>\n<li>altering the source code might change runtime behaviour and the occurrence of the defect.<\/li>\n<li>code added for debugging purposes might be part of the next release, which in my case is more likely.<\/li>\n<\/ul>\n<p>To circumvent this, a symbolic breakpoint is created on <code>foo(char * value)<\/code> by entering the following command into the LLDB CLI:<\/p>\n<pre><code>$ (lldb) br s -n foo<\/code><\/pre>\n<p>This is currently not enough, because the breakpoint stops every time <code>foo(char * value)<\/code> is called, which results in a lot of false positive debugger hits during the debug session. To avoid this, a condition is added to the breakpoint with the purpose of stopping only if the given <code>value<\/code> to <code>foo(...)<\/code>is <code>NULL<\/code>.<\/p>\n<pre><code>$ (lldb) br s -n foo -c \"value == NULL\"<\/code><\/pre>\n<p>The breakpoint will now stop program execution only if the given <code>value<\/code> is <code>NULL<\/code> whereas every other call to <code>foo(...)<\/code> is ignored.<\/p>\n<p>A condition can be more than just a simple comparison. It can be everything whereupon its result resolves to an integer value and the condition is fulfilled if the result is <code>0<\/code>. For example the next breakpoint which is again attached to <code>foo(...)<\/code> uses the C function <code>strcmp<\/code> to halt program execution if <code>value<\/code> is equal to <code>bar<\/code>.<\/p>\n<pre><code>$ (lldb) br s -n foo -c \"(int)strcmp(value, 'bar')\"<\/code><\/pre>\n<h3><span class=\"ez-toc-section\" id=\"MetaBreakpoint-Breakpoints-Modifying-Breakpoints\"><\/span>MetaBreakpoint: Breakpoints Modifying Breakpoints<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Sometimes a breakpoint with a condition might not be the perfect choice to debug a misbehaviour. Let&#8217;s take a look at the following image, the program execution might crash or just misbehave if our well known function <code>foo(...)<\/code> is called through the execution path of the caller represented with the red box. Because all callers use the same argument <code>\"bar\"<\/code> a conditional breakpoint won&#8217;t help to debug this scenario.<\/p>\n<figure><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-17602 size-full\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/metabreakpoint.png\" alt=\"Where to use a MetaBreakpoint\" width=\"829\" height=\"247\" srcset=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/metabreakpoint.png 829w, https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/metabreakpoint-300x89.png 300w, https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/metabreakpoint-768x229.png 768w, https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/metabreakpoint-400x119.png 400w, https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/metabreakpoint-360x107.png 360w\" sizes=\"auto, (max-width: 829px) 100vw, 829px\" \/><\/figure>\n<p>Without further knowledge of how <em>MetaBreakpoints<\/em> (which is not an official name by LLDB, the term is used within the article to describe breakpoints that do not halt program execution and are solely used to alter other breakpoints) can be used, a first approach could be to add a breakpoint at the position <code>foo(\"bar\")<\/code> within the red box. Let&#8217;s assume this is in file <em>file4.c<\/em> at <em>line 3<\/em>. The corresponding breakpoint is:<\/p>\n<pre><code>$ (lldb) br s -f file4.c -l 3<\/code><\/pre>\n<p>A second breakpoint is needed at <code>foo(...)<\/code> which is created by:<\/p>\n<pre><code>$ (lldb) br s -n foo -N bp_foo -d <\/code><\/pre>\n<p>This time the breakpoint gets a name via <code>-N<\/code> which is useful if the breakpoint is referenced later. The parameter <code>-d<\/code> deactivates the breakpoint right from the start. When the first breakpoint is hit, which means the execution path &#8222;is in the red box&#8220;, the command<\/p>\n<pre><code>$ (lldb) br enable -N bp_foo<\/code><\/pre>\n<p>will enable the previously deactivated breakpoint named <code>bp_foo<\/code>. It can be assumed that after the debugger stops again, the caller of <code>foo(...)<\/code> is the one from the red box.<\/p>\n<p>This approach can be completely automated using a MetaBreakpoint. Its purpose is to enable the disabled breakpoint and continue program execution after it has been hit.<\/p>\n<pre class=\"\"><code class=\"shell\">$ (lldb) br s -n foo -N bp_foo -d\r\n\r\n$ (lldb) br s -f file4.c -l 3 -C \"br en bp_foo\" -G true<\/code><\/pre>\n<p>At first a deactivated breakpoint named <code>bp_foo<\/code> on function <code>foo(...)<\/code> is created as already seen in the examples above. Afterwards the MetaBreakpoint is created with two parameters <code>-C \"br en bp_foo\"<\/code> which executes the command that enables the disabled breakpoint and <code>-G true<\/code> to automatically continue program execution after the MetaBreakpoint has been hit.<\/p>\n<p>The technique from above can be useful to follow the critical execution path of a stack trace, by attaching a MetaBreakpoint onto every stack frame position of interest and eventually halt program execution if all preconditions are met.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Example-Usage-of-MetaBreakpoints\"><\/span>Example Usage of MetaBreakpoints<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The previous topic introduced <em>MetaBreakpoints<\/em>\u00a0as a technique that uses breakpoints to alter existing breakpoints or more generally to execute a command and automatically continue program execution.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"printf-like-Debugging\"><\/span>printf()-like Debugging<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>From time to time everything that is needed is a good old <code>printf()<\/code> state to visually indicate what path the program executes or how many times a function has been called. Most of the time this goal is achieved by adding a <code>printf()<\/code> statement in the code. For example like so:<\/p>\n<pre><code class=\"c++\">int main(int argc, char *argv[]) {\r\n\r\n    printf(\"Line 1\");\r\n\r\n    something();\r\n\r\n    printf(\"Line 2\");\r\n\r\n    some_other_thing();\r\n\r\n    printf(\"Line 3\");\r\n\r\n    [...]\r\n\r\n}<\/code><\/pre>\n<p>As mentioned before, this approach has two drawbacks: it alters the current code and might result in seeing this &#8222;feature&#8220; in the next release (information leak, here we go). The same <code>printf()<\/code> behaviour as above can be achieved with a MetaBreakpoint like the one below:<\/p>\n<pre><code class=\"shell\">$ (lldb) br s -p . -X main -f main.c -G true\r\n\r\n  br command add -s python\r\n\r\n  print(\"Line:{}\".format(frame.GetLineEntry().GetLine()))\r\n\r\n  DONE<\/code><\/pre>\n<p>At first, a breakpoint is created with a regular expression <code>-p<\/code> where the expression itself is <code>.<\/code> which matches every line of code. With <code>-X main<\/code> the regular expression is limited to a function named <code>main<\/code> and because <code>main<\/code> is a very common function name which might exist quite a lot, <code>-f main.c<\/code> limits the regular expression even further to a file named <code>main.c<\/code>. As mentioned before <code>-G true<\/code> makes sure, that the breakpoint automatically continues if hit. By then there is an auto-continue breakpoint on each line in function <code>main(...)<\/code>. The subsequent command<\/p>\n<pre><code>$ (lldb) br command add -s python<\/code><\/pre>\n<p>tells LLDB that a multiline command for the last created breakpoint is about to start. By using <code>-s python<\/code> the command itself will use Python as scripting language and its bridging interface to LLDB. In one of the previous examples <code>-C<\/code> is used to execute a command, which is handy for <em>one-liners.<\/em>\u00a0For everything else <code>br command add<\/code> should be preferred. If the command is to be attached to a breakpoint which is not the last created one, the last parameter can be the number of the breakpoint or its name (remember <code>-N<\/code>).<\/p>\n<pre><code class=\"shell\">print(\"Line:{}\".format(frame.GetLineEntry().GetLine()))\r\n\r\nDONE<\/code><\/pre>\n<p>When the bridging interface is used, LLDB wraps the Python code into a function with three parameters: <code>frame<\/code>, <code>bp_loc<\/code>, and <code>dict<\/code>. The current line of source code information can be retrieved from <code>frame<\/code>. By putting everything into a <code>print<\/code> statement, the breakpoint prints each line number it executes into the CLI. Lastly the multiline command is closed by <code>DONE<\/code>.<\/p>\n<p>Further details on how to use the scripting interface with Python can be seen <a href=\"https:\/\/lldb.llvm.org\/use\/python-reference.html\">here<\/a>.<\/p>\n<h4><span class=\"ez-toc-section\" id=\"DRY-and-Commands\"><\/span>DRY and Commands<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>As mentioned before a command is, if not further specified, automatically attached to the last created breakpoint. But a command is not tied to a single breakpoint it can be either attached to multiple breakpoints by adding the number of\u00a0 breakpoints at the end of <code>br command add<\/code>,<\/p>\n<pre><code class=\"shell\">$ (lldb) br command add 1 2 3 4\r\n\r\n$ (lldb) br command add 1-4<\/code><\/pre>\n<p>or if the same name, e.g. <code>-N bp_printf<\/code> is used for a couple of breakpoints, they can all get the same command by using that name during command creation.<\/p>\n<pre><code>$ (lldb) br command add bp_printf<\/code><\/pre>\n<h3><span class=\"ez-toc-section\" id=\"Mute-AVPlayer-on-Initialisation\"><\/span>Mute AVPlayer on Initialisation<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>In one of my last projects an instance of <em>AVPlayer<sup><a id=\"fnr1-30761\" class=\"footnote\" title=\"see footnote\" href=\"#fn1-30761\">1<\/a><\/sup><\/em> has been used with the purpose of immediately starting to play an audio\/video stream after the app starts, which I found a little bit annoying. There have been four options to choose from to stop this\u2014from my point of view\u2014unwanted behaviour:<\/p>\n<ol>\n<li>Mute the computer during development to mute the iOS simulator, which is not acceptable because my music would also be gone.<\/li>\n<li>Mute the AVPlayer via the apps UI within the iOS Simulator. Not acceptable either, takes too much effort.<\/li>\n<li>Don&#8217;t use the Xcode simulator anymore and deploy on a real iDevice and mute it. Not an option, takes longer to deploy than on the simulator and switching screen size is not so easy, especially if there is only a single device available.<\/li>\n<li>Use LLDB and fix it. That&#8217;s the way to go.<\/li>\n<\/ol>\n<p>The goal is to mute an <em>AVPlayer<\/em> instance immediately after its creation. The problem is, that <em>AVPlayer<\/em> is part of Apple&#8217;s ecosystem and sources are not publicly available. Furthermore LLDB does not have an option out of the box to set a breakpoint at the end of a function.<\/p>\n<h4><span class=\"ez-toc-section\" id=\"Solution-1\"><\/span>Solution #1<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>A first and simple approach is to just add a breakpoint onto the next line after <em>AVPlayer<\/em> is initialised.<\/p>\n<pre><code class=\"swift\">func do() {\r\n\r\n  let player = AVPlayer(playerItem: nil)\r\n\r\n  [...]\r\n\r\n}<\/code><\/pre>\n<p>Let&#8217;s assume that the example code from above is in file <code>Player.swift<\/code> and the initialisation is in line 2. The breakpoint to mute the <em>AVPlayer<\/em> will look like this:<\/p>\n<pre><code>$ (lldb) br s -l 3 -f Player.swift -C \"call player.isMuted = true\" -G true<\/code><\/pre>\n<p>The only thing that might not look familiar is the command itself. All the executed commands so far were either a Python script or a breakpoint instruction. <code>call<\/code>, which is an abbreviation for <code>expression --<\/code>, evaluates an expression on the current thread of the program that is being debugged. So, if the breakpoint is hit, LLDB evaluates the expression <code>player.isMuted = true<\/code> and mutes the current instance of <em>AVPlayer<\/em>.<\/p>\n<p>This solution might not last forever because the breakpoint is tied to a specific line and this might not be the only place an <em>AVPlayer<\/em> is initialised.<\/p>\n<h4><span class=\"ez-toc-section\" id=\"Solution-2\"><\/span>Solution #2<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>To bypass both flaws the only solution that will work reliably is to either add a breakpoint at the end of the initialisation function or immediately after it. Before a breakpoint can be added to the end of <code>AVPlayer(playerItem: nil)<\/code> which eventually calls <code>AVPlayer()<\/code> or if written in Objective-C <code>[AVPlayer init]<\/code> its current address space must be resolved.<\/p>\n<pre><code class=\"shell\">$ (lldb) image lookup -vrn \"\\[AVPlayer init\\]\"\r\n\r\n    1 match found in [...] AVFoundation:\r\n\r\n    Address: AVFoundation[0x00000000000852e4]\r\n\r\n    [...]\r\n\r\n    [0x00007fff208aa2e4-0x00007fff208aa854), name=\"-[AVPlayer init]\"\r\n\r\n    [...]<\/code><\/pre>\n<p>The result contains the relative address <em>0x852e4<\/em> within <em>AVFoundation<\/em> (the module\/library <em>AVPlayer<\/em> belongs to) and the current absolute address space <em>[0x7fff208aa2e4-0x7fff208aa854)<\/em>. With this information it is possible to create a breakpoint at the end of the <code>[AVPlayer init]<\/code> function via<\/p>\n<pre><code>$ (lldb) br s -a 0x852e4+0x56f -s AVFoundation<\/code><\/pre>\n<p>The important parameter in this case is\u00a0<code>-s AVFoundation<\/code> to be able to use relative or file based addresses instead of absolute addresses which change every time the binary is executed due to <a href=\"https:\/\/en.wikipedia.org\/wiki\/Address_space_layout_randomization\">ASLR<\/a>. The question is how to execute the mute expression, because within the <em>AVFoundation<\/em> library where the breakpoint now resides there are no variables available. This can be checked with the <code>frame variable<\/code> command.<\/p>\n<p>Actually the variables are still available but their names are far from being intuitively readable, because they are just addresses\/values on the stack\/heap or register. One of these registers is\u2014on x86_64 architectures\u2014<code>rax<\/code> which contains the result value of a function <strong>after<\/strong> it returns. This means, that if the above breakpoint is hit the <code>rax<\/code> register contains the return value of <code>[AVPlayer init]<\/code> which is a pointer to the created <em>AVPlayer<\/em> instance on the heap.<\/p>\n<p>With all information from above the final breakpoint to achieve our goal looks like this:<\/p>\n<pre><code class=\"shell\">$ (lldb) br s -a 0x852e4+0x56f -s AVFoundation\r\n\r\n  br command add\r\n\r\n  exp -l objc -- [(AVPlayer *)$rax setMuted: @YES]\r\n\r\n  continue\r\n\r\n  DONE<\/code><\/pre>\n<p>Although the example code is in Swift, <code>expression<\/code> is used with <code>-l objc<\/code> and instructs LLDB to evaluate the following expression as an ObjC construct, as it is much easier to operate and cast pointers in ObjC than it is in Swift. Finally <code>continue<\/code> automatically continues program execution after the command did execute which is equivalent to using <code>-G true<\/code>.<\/p>\n<h4><span class=\"ez-toc-section\" id=\"Solution-3\"><\/span>Solution #3<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>The solution does have one drawback, besides being tied to x86_64 platforms, which in iOS development is the architecture of the simulator, it might not work or must be updated every time the iOS version changes, because the internal libraries may change and with them their relative addresses. But this can be solved too, by extending the solution from above with a symbolic breakpoint onto <code>[AVPlayer init]<\/code>.<\/p>\n<pre><code class=\"shell\">$ (lldb) br s -S \"-[AVPlayer init]\" -K false\r\n\r\n    br command add\r\n\r\n    settings set target.language objc\r\n\r\n    br s -a `(unsigned long)*(unsigned long *)$rsp` -o true -C \"exp -l objc -- [(AVPlayer *)$rax setMuted: @YES]\" -G true\r\n\r\n    settings set target.language swift\r\n\r\n    continue\r\n\r\n    DONE<\/code><\/pre>\n<p>Let&#8217;s dig into this line by line.<\/p>\n<pre><code>$ (lldb) br s -S \"-[AVPlayer init]\" -K false<\/code><\/pre>\n<p>First a symbolic breakpoint is added onto the initialisation function of <em>AVPlayer<\/em>. By using <code>-S<\/code> the name of the selector (in ObjC functions are normally not called directly instead they are resolved by the runtime via a selector) instead of a function name is used to specify the location the breakpoint is attached to. With <code>-K false<\/code> the function prologue is not skipped and the breakpoint is attached to the function as early as possible. This is important if values from the caller stack are referenced which this solution does.<\/p>\n<pre><code>settings set target.language objc<\/code><\/pre>\n<p>The default language interpreter LLDB uses from now on is ObjC, because it is easier to use pointers, furthermore expressions in backticks like <code>`$rsp`<\/code> are resolved too, which does not work if the target language is Swift.<\/p>\n<pre><code>$ (lldb) br s -a `(unsigned long)*(unsigned long *)$rsp` -o true -C \"exp -l objc -- [(AVPlayer *)$rax setMuted: @YES]\" -G true<\/code><\/pre>\n<p><code>$rsp<\/code> is the register that points onto the current top of the stack which contains the return address <code>[AVPlayer init]<\/code> calls immediately after initialisation did finish. Which means the above breakpoint will be hit after <em>AVPlayer<\/em> is fully initialised and before any subsequent code is executed. By using <code>-o true<\/code> the breakpoint will be deleted after first hit to ensure that the command is only executed once. The breakpoint command itself is the same that has already been used within the relative address solution.<\/p>\n<p>This solution is still tied to x86_64 architecture platforms but it does not matter anymore which version of iOS is running. Due to the usage of a symbolic breakpoint as the entrance, the subsequent breakpoints can safely use absolut address information provided by the currently running binary.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Control-Flow-Manipulation\"><\/span>Control Flow Manipulation<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Changing the behaviour of an application during developmentin most instances involves to recompile parts of the project. This can be time consuming or just annoying. Luckily LLDB has a couple of commands in its toolbox that allows changing the control flow during runtime without the need to recompile the binary. Furthermore, if tied to a breakpoint the control flow changes can be switched on and off and automatically set up.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"thread-jump\"><\/span>thread jump<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre><code class=\"c\">static int can_pass() {\r\n\r\n    return 0;\r\n\r\n}\r\n\r\nint main(int argc, char *argv[]) {\r\n\r\n    if (0 == can_pass()) {\r\n\r\n        printf(\"Better luck next time\\n\");\r\n\r\n        exit(1);\r\n\r\n    }\r\n\r\n    printf(\"Hello lldb\\n\");\r\n\r\n}<\/code><\/pre>\n<p>Take the example code from above, currently there is no chance it prints <code>Hello lldb<\/code>. This can be\u2014of course\u2014changed without changing the code itself, by using the <code>thread<\/code> command. The command itself has a couple of subcommands with the primarily focus on changing, stepping, and showing information of the current thread. One of these subcommands is <code>jump<\/code>, which allows to change the programs counter and therefore the order of program execution.<\/p>\n<p>The following breakpoint which is attached to <code>main<\/code>\u00a0uses <code>thread jump<\/code>\u00a0to alter the control flow every time <code>main<\/code>\u00a0is called.<\/p>\n<pre class=\"\"><code>$ (lldb) br s -n main -C \"thread jump -b 4\" -G true<\/code><\/pre>\n<p>The important part of the auto-continue breakpoint is the command <code>thread jump -b 4<\/code> which results in omitting the next 4 lines of code before continuing code execution and eventually printing <code>Hello lldb<\/code>.<\/p>\n<p>One of the disadvantages of <code>thread jump<\/code> is that it can only be used with absolute jump information, like <em>jump over the next x lines<\/em>, <em>jump to line in file<\/em>, or <em>jump to absolut address<\/em>. In most cases these kind of information are not stable during development and might therefore change, whereupon the breakpoint that injects the <em>jump<\/em> command has to be updated accordingly\u00a0to work as expected.<\/p>\n<h3 id=\"thread-return\"><span class=\"ez-toc-section\" id=\"thread-return\"><\/span>thread return<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>The mentioned disadvantage of <code>thread jump<\/code> can be avoided by using a different technique to change control flow behaviour. Instead of manipulating the affected lines of code directly the idea is to manipulate other parts of the program which in turn results in the desired behaviour. For the given example this means changing the return value of <code>can_pass()<\/code> from <code>0<\/code> to <code>1<\/code>.<\/p>\n<p>Which, of course, can be done through LLDB. The command to use is\u00a0<code>thread<\/code>\u00a0just like before, but this time with the subcommand <code>return<\/code> to prematurely return from a stack frame, thereby short-circuiting its execution.<\/p>\n<p>To manipulate the return value of <em>can_pass()<\/em> a symbolic breakpoint is added to it.<\/p>\n<pre><code>$ (lldb) br s -n can_pass -C \"thread return 1\" -G true<\/code><\/pre>\n<p>The composition of the auto continuing breakpoint that acts as the injector is always the same. This time the command short-circuits the function <code>can_pass()<\/code> and automatically puts the return value <code>1<\/code> into the desired return register of the current architecture. Unfortunately the usage of return values is limited to integer and float types. This means a command of the form<\/p>\n<pre><code>-C \"thread return 'foo'\"<\/code><\/pre>\n<p>won&#8217;t work and extra efforts have to be taken for this use case, which I&#8217;ll show next.<\/p>\n<pre><code class=\"c\">static char const * secret() {\r\n\r\n    return \"foo\";\r\n\r\n}\r\n\r\nint main(int argc, char *argv[]) {\r\n\r\n    if (strcmp(\"bar\", secret())) {\r\n\r\n        printf(\"Better luck next time\\n\");\r\n\r\n        exit(1);\r\n\r\n    }\r\n\r\n    printf(\"Hello lldb\\n\");\r\n\r\n}<\/code><\/pre>\n<p>To manipulate the return value of <code>secret()<\/code> so it matches the already hard coded one, a new <em>String<\/em> has to be generated. As mentioned before LLDB can evaluate expression on the fly as long as it is valid C\/ObjC\/C++\/Swift<sup><a id=\"fnr2-30761\" class=\"footnote\" title=\"see footnote\" href=\"#fn2-30761\">2<\/a><\/sup> code. A new String value is created with LLDB by executing:<\/p>\n<pre><code>expression -- auto $bar = \"bar\"<\/code><\/pre>\n<p>The only thing that is left is to return the actual string value, which is done by returning the pointer address of the first character of the string.<\/p>\n<pre><code>thread return `$bar`<\/code><\/pre>\n<p>The backticks around <em>$bar<\/em> are important so that the variable is evaluated to its actual value before being processed any further. The result is the needed pointer address, which is nothing more than an integer value.<\/p>\n<p>With all the explanation from above the <em>production ready<\/em> breakpoint looks like this:<\/p>\n<pre><code class=\"shell\">$ (lldb) br s -n secret -G true\r\n\r\n  br command add\r\n\r\n  expression -- auto $bar = \"bar\"\r\n\r\n  thread return `$bar` DONE<\/code><\/pre>\n<h3><span class=\"ez-toc-section\" id=\"Binary-Patch-Breakpoints\"><\/span>Binary Patch Breakpoints<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>There is only one caveat while using control flow manipulation commands like <code>thread return<\/code> or <code>thread jump<\/code>: they slow down program execution. The impact is negligible as long as the manipulated function is called a couple of times, but is noticeable if called e.g. 60 times per second (maybe it&#8217;s in a ScrollView and every time a new cell is rendered a breakpoint kicks in to manipulate the code).<\/p>\n<p>If the injection point is chosen well to manipulate the control flow, e.g. it can be reduced to a <code>0\/1<\/code>\u00a0decision, a possible solution is to binary patch the function.<\/p>\n<p>Taking the code example from <a href=\"#thread-return\">thread return<\/a> the idea is to change<\/p>\n<pre><code class=\"c\">static int can_pass() {\r\n\r\n    return 0;\r\n\r\n}<\/code><\/pre>\n<p>into<\/p>\n<pre><code class=\"c\">static int can_pass() {\r\n\r\n    return 1;\r\n\r\n}<\/code><\/pre>\n<p>after the binary has been compiled and is already executing.<\/p>\n<p>The current address of the function is determined via a breakpoint, which shouldn&#8217;t be a surprise by now, and the usage of the Python bridge, which offers a convenient way to change memory content of the current running process.<\/p>\n<p>The last part that is missing to accomplish the goal is the actual binary patch. This can be achieved e.g. by compiling a small program and disassemble its content including op-codes with <code>otool -tVj a.out<\/code>. The result should look similar to the one below.<\/p>\n<pre><code class=\"assembler\">_can_pass:\r\n\r\n55     push %rbp\r\n\r\n6a 01  push $0x1\r\n\r\n58     pop  %rax\r\n\r\n5d     pop  %rbp\r\n\r\nc3     ret<\/code><\/pre>\n<p>Putting all together the resulting binary patch breakpoint that overwrites <code>can_pass()<\/code> to always return <code>1<\/code> instead of <code>0<\/code> is:<\/p>\n<pre class=\"\"><code class=\"shell\">$ (lldb) br s -n can_pass -o true -K false\r\n\r\n  br command add -s python\r\n\r\n  patch = '\\x55\\x6a\\x01\\x58\\x5d\\xc3'\r\n\r\n  addr = bp_loc.GetLoadAddress()\r\n\r\n  error = lldb.SBError()\r\n\r\n  proc = frame.GetThread().GetProcess()\r\n\r\n  result = proc.WriteMemory(addr, patch, error)\r\n\r\n  proc.Continue()\r\n\r\n  DONE<\/code><\/pre>\n<p>Caution: this will only work if the binary patch takes less or equal space than the function being replaced, otherwise unknown parts will be overwritten without knowing the impact which results most likely in a program crash.<\/p>\n<p>Unlike the solutions before, this patch is persistent and therefore not detachable. To withdraw the changes, the breakpoint has to be disabled and the binary needs to be restarted.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Persisting-Breakpoints\"><\/span>Persisting Breakpoints<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Instead of adding a breakpoint every time the binary is started manually, like in the examples of this article, the <code>~\/.lldbinit<\/code> file can be used to:<\/p>\n<ol>\n<li>Add settings that are used every time LLDB is started, like\n<pre><code>settings set target.x86-disassembly-flavor intel<\/code><\/pre>\n<p>to change the disassembly flavour from AT&amp;T to Intel.<\/li>\n<li>Add command aliases to define custom commands that are used often.<\/li>\n<li>Execute LLDB commands, like the ones from the article to automatically inject a breakpoint during startup.<\/li>\n<\/ol>\n<p>If LLDB commands are added directly into <code>~\/.lldbinit<\/code> it should be noted that they are executed every time LLDB starts, no matter which binary is being debugged, which might result in unexpected behaviour.<\/p>\n<p>This can be avoided by adding the LLDB commands into separate project-related files and using\u00a0<code>command source &lt;filename&gt;<\/code> within the <code>~\/.lldbinit<\/code> file to load all LLDB commands within that file. There is an LLDB plugin available called <a href=\"https:\/\/github.com\/obayer\/trampoline\">Trampoline<\/a> which uses the above mechanism and automatically loads custom lldb init files depending on the current target architecture and binary name.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Conclusion\"><\/span>Conclusion<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>LLDB is a very versatile tool during development and can do a lot more than just adding breakpoints and stopping execution when they are hit. The article did only cover a small amount of the capabilities of LLDB, others being:<\/p>\n<ul>\n<li>Reading and writing memory<\/li>\n<li>Finding patterns in memory<\/li>\n<li>Dumping complete memory sections<\/li>\n<li>Reading and writing register values<\/li>\n<li>Reloading libraries during execution<\/li>\n<li>Developing custom plugins in C++\/Python<\/li>\n<li>Watchpoints to observe access to memory areas<\/li>\n<li>Disassembling the current binary<\/li>\n<\/ul>\n<p>and many more.<\/p>\n<p>Use <code>help<\/code> to see a comprehensive list of all available commands and aliases. To drill into the subcommands of each command use <code>help &lt;command&gt;<\/code>.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Read-on\"><\/span>Read on<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Are you looking for support in your app development process? Have a look at <a href=\"https:\/\/www.inovex.de\/en\/our-services\/apps\/\">our offerings<\/a>!<\/p>\n<div class=\"footnotes\">\n<hr \/>\n<ol>\n<li id=\"fn1-30761\">Commonly used on iOS to play audio and video streams <a class=\"reversefootnote\" title=\"return to article\" href=\"#fnr1-30761\">\u21a9\ufe0e<\/a><\/li>\n<li id=\"fn2-30761\">If LLDB is used with Swift support, which is the default on macOS. <a class=\"reversefootnote\" title=\"return to article\" href=\"#fnr2-30761\">\u21a9\ufe0e<\/a><\/li>\n<\/ol>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>tl;dr Ever wanted to change some behaviour of your application during development without the need to recompile it? LLDB\u00a0has got you covered. This article explains how LLDB is used through its CLI, how simple breakpoints are created, and finally how they can be used to non-destructively alter current application behaviour.<\/p>\n","protected":false},"author":136,"featured_media":17674,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"ep_exclude_from_search":false,"footnotes":""},"tags":[510],"service":[420],"coauthors":[{"id":136,"display_name":"Oliver Bayer","user_nicename":"obayer"}],"class_list":["post-17592","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tag-apps-2","service-apps"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>LLDB: Patch Your Code with Breakpoints - inovex GmbH<\/title>\n<meta name=\"description\" content=\"Ever wanted to change some behaviour of your application during development without the need to recompile it? LLDB\u00a0has got you covered. This article explains how LLDB is used through its CLI, how simple breakpoints are created, and finally how they can be used to non-destructively alter current application behaviour.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"LLDB: Patch Your Code with Breakpoints - inovex GmbH\" \/>\n<meta property=\"og:description\" content=\"Ever wanted to change some behaviour of your application during development without the need to recompile it? LLDB\u00a0has got you covered. This article explains how LLDB is used through its CLI, how simple breakpoints are created, and finally how they can be used to non-destructively alter current application behaviour.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/\" \/>\n<meta property=\"og:site_name\" content=\"inovex GmbH\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/inovexde\" \/>\n<meta property=\"article:published_time\" content=\"2019-11-26T07:30:36+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-11-21T15:11:52+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/lldb-debugger-breakpoints-s.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1920\" \/>\n\t<meta property=\"og:image:height\" content=\"1080\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Oliver Bayer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/lldb-debugger-breakpoints-s-1024x576.png\" \/>\n<meta name=\"twitter:creator\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:site\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Oliver Bayer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"22\u00a0Minuten\" \/>\n\t<meta name=\"twitter:label3\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data3\" content=\"Oliver Bayer\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/\"},\"author\":{\"name\":\"Oliver Bayer\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/762ae86fe2d464753ad2c05c568c400f\"},\"headline\":\"LLDB: Patch Your Code with Breakpoints\",\"datePublished\":\"2019-11-26T07:30:36+00:00\",\"dateModified\":\"2022-11-21T15:11:52+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/\"},\"wordCount\":3802,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/lldb-debugger-breakpoints-s.png\",\"keywords\":[\"Apps\"],\"articleSection\":[\"Applications\",\"English Content\",\"General\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/\",\"url\":\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/\",\"name\":\"LLDB: Patch Your Code with Breakpoints - inovex GmbH\",\"isPartOf\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/lldb-debugger-breakpoints-s.png\",\"datePublished\":\"2019-11-26T07:30:36+00:00\",\"dateModified\":\"2022-11-21T15:11:52+00:00\",\"description\":\"Ever wanted to change some behaviour of your application during development without the need to recompile it? LLDB\u00a0has got you covered. This article explains how LLDB is used through its CLI, how simple breakpoints are created, and finally how they can be used to non-destructively alter current application behaviour.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#primaryimage\",\"url\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/lldb-debugger-breakpoints-s.png\",\"contentUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/lldb-debugger-breakpoints-s.png\",\"width\":1920,\"height\":1080,\"caption\":\"A stylized terminal with LLDB CLI an breakpoints\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.inovex.de\/de\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"LLDB: Patch Your Code with Breakpoints\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.inovex.de\/de\/#website\",\"url\":\"https:\/\/www.inovex.de\/de\/\",\"name\":\"inovex GmbH\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.inovex.de\/de\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\",\"name\":\"inovex GmbH\",\"url\":\"https:\/\/www.inovex.de\/de\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png\",\"contentUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png\",\"width\":1921,\"height\":1081,\"caption\":\"inovex GmbH\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/inovexde\",\"https:\/\/x.com\/inovexgmbh\",\"https:\/\/www.instagram.com\/inovexlife\/\",\"https:\/\/www.linkedin.com\/company\/inovex\",\"https:\/\/www.youtube.com\/channel\/UC7r66GT14hROB_RQsQBAQUQ\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/762ae86fe2d464753ad2c05c568c400f\",\"name\":\"Oliver Bayer\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/image\/1d7623e7f32f4e8541fc1cb76cc9f6ae\",\"url\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/IMG_0716-scaled-96x96.jpeg\",\"contentUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/IMG_0716-scaled-96x96.jpeg\",\"caption\":\"Oliver Bayer\"},\"description\":\"Mobile Entwicklung mit iOS und Flutter. Liebt die Automatisierung mittels fastlane. Erstes Mobile Device: Siemens SL45i mit J2ME.\",\"url\":\"https:\/\/www.inovex.de\/de\/blog\/author\/obayer\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"LLDB: Patch Your Code with Breakpoints - inovex GmbH","description":"Ever wanted to change some behaviour of your application during development without the need to recompile it? LLDB\u00a0has got you covered. This article explains how LLDB is used through its CLI, how simple breakpoints are created, and finally how they can be used to non-destructively alter current application behaviour.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/","og_locale":"de_DE","og_type":"article","og_title":"LLDB: Patch Your Code with Breakpoints - inovex GmbH","og_description":"Ever wanted to change some behaviour of your application during development without the need to recompile it? LLDB\u00a0has got you covered. This article explains how LLDB is used through its CLI, how simple breakpoints are created, and finally how they can be used to non-destructively alter current application behaviour.","og_url":"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/","og_site_name":"inovex GmbH","article_publisher":"https:\/\/www.facebook.com\/inovexde","article_published_time":"2019-11-26T07:30:36+00:00","article_modified_time":"2022-11-21T15:11:52+00:00","og_image":[{"width":1920,"height":1080,"url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/lldb-debugger-breakpoints-s.png","type":"image\/png"}],"author":"Oliver Bayer","twitter_card":"summary_large_image","twitter_image":"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/lldb-debugger-breakpoints-s-1024x576.png","twitter_creator":"@inovexgmbh","twitter_site":"@inovexgmbh","twitter_misc":{"Verfasst von":"Oliver Bayer","Gesch\u00e4tzte Lesezeit":"22\u00a0Minuten","Written by":"Oliver Bayer"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#article","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/"},"author":{"name":"Oliver Bayer","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/762ae86fe2d464753ad2c05c568c400f"},"headline":"LLDB: Patch Your Code with Breakpoints","datePublished":"2019-11-26T07:30:36+00:00","dateModified":"2022-11-21T15:11:52+00:00","mainEntityOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/"},"wordCount":3802,"commentCount":0,"publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/lldb-debugger-breakpoints-s.png","keywords":["Apps"],"articleSection":["Applications","English Content","General"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/","url":"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/","name":"LLDB: Patch Your Code with Breakpoints - inovex GmbH","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#primaryimage"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/lldb-debugger-breakpoints-s.png","datePublished":"2019-11-26T07:30:36+00:00","dateModified":"2022-11-21T15:11:52+00:00","description":"Ever wanted to change some behaviour of your application during development without the need to recompile it? LLDB\u00a0has got you covered. This article explains how LLDB is used through its CLI, how simple breakpoints are created, and finally how they can be used to non-destructively alter current application behaviour.","breadcrumb":{"@id":"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#primaryimage","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/lldb-debugger-breakpoints-s.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2019\/11\/lldb-debugger-breakpoints-s.png","width":1920,"height":1080,"caption":"A stylized terminal with LLDB CLI an breakpoints"},{"@type":"BreadcrumbList","@id":"https:\/\/www.inovex.de\/de\/blog\/lldb-patch-your-code-with-breakpoints\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.inovex.de\/de\/"},{"@type":"ListItem","position":2,"name":"LLDB: Patch Your Code with Breakpoints"}]},{"@type":"WebSite","@id":"https:\/\/www.inovex.de\/de\/#website","url":"https:\/\/www.inovex.de\/de\/","name":"inovex GmbH","description":"","publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.inovex.de\/de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/www.inovex.de\/de\/#organization","name":"inovex GmbH","url":"https:\/\/www.inovex.de\/de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","width":1921,"height":1081,"caption":"inovex GmbH"},"image":{"@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/inovexde","https:\/\/x.com\/inovexgmbh","https:\/\/www.instagram.com\/inovexlife\/","https:\/\/www.linkedin.com\/company\/inovex","https:\/\/www.youtube.com\/channel\/UC7r66GT14hROB_RQsQBAQUQ"]},{"@type":"Person","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/762ae86fe2d464753ad2c05c568c400f","name":"Oliver Bayer","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/image\/1d7623e7f32f4e8541fc1cb76cc9f6ae","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/IMG_0716-scaled-96x96.jpeg","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/IMG_0716-scaled-96x96.jpeg","caption":"Oliver Bayer"},"description":"Mobile Entwicklung mit iOS und Flutter. Liebt die Automatisierung mittels fastlane. Erstes Mobile Device: Siemens SL45i mit J2ME.","url":"https:\/\/www.inovex.de\/de\/blog\/author\/obayer\/"}]}},"_links":{"self":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/17592","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/users\/136"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/comments?post=17592"}],"version-history":[{"count":1,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/17592\/revisions"}],"predecessor-version":[{"id":39481,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/17592\/revisions\/39481"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media\/17674"}],"wp:attachment":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media?parent=17592"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/tags?post=17592"},{"taxonomy":"service","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/service?post=17592"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/coauthors?post=17592"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}