Jekyll2020-02-15T23:18:53+00:00https://www.ryanipete.com/blog/feed.xmlLow LevelNotes on debugging from an iOS developerRyan Petersonhttps://www.ryanipete.comUIDebuggingInformationOverlay2017-05-25T00:00:00+00:002017-05-25T00:00:00+00:00https://www.ryanipete.com/blog/ios/swift/objective-c/uidebugginginformationoverlay<p><strong>Update, December 9, 2017:</strong> This overlay still exists, but this post’s instructions don’t work on iOS 11 and later. In an update to his excellent book, <a href="https://store.raywenderlich.com/products/advanced-apple-debugging-and-reverse-engineering">Advanced Apple Debugging and Reverse Engineering</a>, <a href="https://twitter.com/LOLgrep">Derek Selander</a> describes how to get the panel working in iOS 11. He’s generously posted the chapter for free <a href="https://www.raywenderlich.com/177890/swizzling-in-ios-11-with-uidebugginginformationoverlay">here</a>.</p>
<hr />
<p>While browsing UIKit’s private headers recently, I came across a class that I hadn’t seen before - <code class="language-plaintext highlighter-rouge">UIDebuggingInformationOverlay</code>. A Google search didn’t turn up much info, so figured I’d write a short description of what I’ve found.</p>
<p><code class="language-plaintext highlighter-rouge">UIDebuggingInformationOverlay</code> is a private <code class="language-plaintext highlighter-rouge">UIWindow</code> subclass created by Apple, presumably to help developers and designers debug Apple’s own iOS apps.</p>
<p>When enabled, the window floats over your app’s content, like so:</p>
<p><img src="https://www.ryanipete.com/blog/assets/images/uidebugginginformationoverlay_0.png" width="320px" alt="UIDebuggingInformationOverlay" itemprop="image" /></p>
<p>In this post, I’ll show you how to make it display. I’ll also summarize its features, at least as I understand them.</p>
<h1>How to show UIDebuggingInformationOverlay</h1>
<p>There are two steps needed to show <code class="language-plaintext highlighter-rouge">UIDebuggingInformationOverlay</code> in all its glory:</p>
<ol>
<li>Call <code class="language-plaintext highlighter-rouge">[UIDebuggingInformationOverlay prepareDebuggingOverlay]</code> - I’m not sure exactly what this method does, but the overlay will be empty if you don’t call it.</li>
<li>Call <code class="language-plaintext highlighter-rouge">[[UIDebuggingInformationOverlay overlay] toggleVisibility]</code> - This shows the overlay window (assuming it’s not already visible).</li>
</ol>
<p>Because the class and its methods are private, you’ll need to jump through a few hoops to get the code to compile. One approach is to use the global ‘NSClassFromString’ and ‘NSSelectorFromString’ functions. In Swift, this approach looks something like:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">overlayClass</span> <span class="o">=</span> <span class="kt">NSClassFromString</span><span class="p">(</span><span class="s">"UIDebuggingInformationOverlay"</span><span class="p">)</span> <span class="k">as?</span> <span class="kt">UIWindow</span><span class="o">.</span><span class="k">Type</span>
<span class="n">_</span> <span class="o">=</span> <span class="n">overlayClass</span><span class="p">?</span><span class="o">.</span><span class="nf">perform</span><span class="p">(</span><span class="kt">NSSelectorFromString</span><span class="p">(</span><span class="s">"prepareDebuggingOverlay"</span><span class="p">))</span>
<span class="k">let</span> <span class="nv">overlay</span> <span class="o">=</span> <span class="n">overlayClass</span><span class="p">?</span><span class="o">.</span><span class="nf">perform</span><span class="p">(</span><span class="kt">NSSelectorFromString</span><span class="p">(</span><span class="s">"overlay"</span><span class="p">))</span><span class="o">.</span><span class="nf">takeUnretainedValue</span><span class="p">()</span> <span class="k">as?</span> <span class="kt">UIWindow</span>
<span class="n">_</span> <span class="o">=</span> <span class="n">overlay</span><span class="p">?</span><span class="o">.</span><span class="nf">perform</span><span class="p">(</span><span class="kt">NSSelectorFromString</span><span class="p">(</span><span class="s">"toggleVisibility"</span><span class="p">))</span>
</code></pre></div></div>
<p>However you choose to do it, be sure that the code doesn’t make it into your App Store build, else you’re likely to get rejected.</p>
<p><strong>Update, May 26, 2017:</strong> Thanks to <a href="https://www.linkedin.com/in/brycepauken/">Bryce Pauken</a>, who discovered that once you’ve called <code class="language-plaintext highlighter-rouge">[UIDebuggingInformationOverlay prepareDebuggingOverlay]</code>, you can just tap the status bar with two fingers to show the console. No need to call <code class="language-plaintext highlighter-rouge">toggleVisibility</code>.</p>
<p><strong>Update, June 2, 2017:</strong> More from Bryce:</p>
<blockquote>
<p>I went through a disassembler (Hopper!) because I was curious about what prepareDebuggingOverlay did as well.
Here’s part of the output. Even before parsing through it, statusBarWindow + numberOfTouchesRequired jumps out quickly enough:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>r14 = [[*_UIApp statusBarWindow] retain];
r15 = [UITapGestureRecognizer alloc];
rbx = [[UIDebuggingInformationOverlay overlay] retain];
r12 = [r15 initWithTarget:rbx action:@selector(_handleActivationGesture:)];
[rbx release];
[r12 setNumberOfTouchesRequired:0x2];
[r12 setNumberOfTapsRequired:0x1];
[r14 addGestureRecognizer:r12];
</code></pre></div> </div>
<p>Another fun takeaway from Hopper — there actually is a spot in UIKit where this method is called:
(<code class="language-plaintext highlighter-rouge">-[UIApplication _runWithMainScene:transitionContext:completion:]</code>, seems to be called during app launch) which after some more digging, seems to enable the debug overlay if 1) <code class="language-plaintext highlighter-rouge">CPIsInternalDevice()</code> returns true, and 2) <code class="language-plaintext highlighter-rouge">UserDefaults(suiteName: "com.apple.UIKit")</code> has a value of true for “DebuggingOverlayEnabled”. No information there that makes this nicer to enable, but still fun food for thought :)</p>
</blockquote>
<h1>What UIDebuggingInformationOverlay can do</h1>
<p>As you can see from the above screenshot, the overlay provides seven features. I’ll give a brief overview of the first six. I wasn’t able to get the ‘System Color Audit’ screen to show me anything, send me a message if you have better luck.</p>
<h2>The 'View Hierarchy' screen</h2>
<p>This screen shows what you’d probably expect; a list of views in the selected window. From here, you can inspect any view’s details, including its frame and instance variables. You can also switch between windows if you have more than one, or are just curious to see how a system window is built.</p>
<p><img src="https://www.ryanipete.com/blog/assets/images/uidebugginginformationoverlay_viewhierarchy.png" width="320px" alt="'View Hierarchy' screen" itemprop="image" />
<img src="https://www.ryanipete.com/blog/assets/images/uidebugginginformationoverlay_viewhierarchyinfo.png" width="320px" alt="'View Hierarchy' info screen" itemprop="image" /></p>
<h2>The 'VC Hierarchy' screen</h2>
<p>You can probably predict what this screen does as well. It’s very similar to the ‘View Hierarchy’ screen, except that it shows the hierarchy of active view controllers. From here, you can inspect any view controller’s details, including its view. You can also see whether the view controller is presenting a modal or is itself being presented.</p>
<p><img src="https://www.ryanipete.com/blog/assets/images/uidebugginginformationoverlay_vchierarchy.png" width="320px" alt="'VC Hierarchy' screen" itemprop="image" /></p>
<h2>The 'Ivar Explorer' screen</h2>
<p>This screen gives you access to the <code class="language-plaintext highlighter-rouge">UIApplication</code> instance’s variables. More importantly, any object variables can also be explored. This includes the app delegate which, depending on your app’s structure, might provide a handy entry point into your custom objects.</p>
<p><img src="https://www.ryanipete.com/blog/assets/images/uidebugginginformationoverlay_ivarexplorer.png" width="320px" alt="'Ivar Explorer' screen" itemprop="image" /></p>
<h2>The 'Measure' screen</h2>
<p>This is one of the cooler features of the overlay, in my opinion. It lets you measure dimensions (in points) of the screen’s elements. First, select whether you want to see measurements on the ‘Horizontal’ or ‘Vertical’ axis. Then drag your finger along the screen, using the magnified viewer inside the console to assist you. There are two modes:</p>
<p>The default mode ignores view boundaries. As far as I can tell, this mode treats the screen as a single rasterized image, and uses changes in color as boundaries for potential measurements. For example, in the screenshot below, I am able to measure the distance between the end of a label’s text and the edge of the screen:</p>
<p><img src="https://www.ryanipete.com/blog/assets/images/uidebugginginformationoverlay_measure.png" width="320px" alt="Ryan Peterson" itemprop="image" /></p>
<p>“View mode”, on the other hand, displays the size of the subview in focus. Drag your finger over a view to see the selected axis’s dimension. In this screenshot, I’m measuring the height of the textfield at the top of the screen:</p>
<p><img src="https://www.ryanipete.com/blog/assets/images/uidebugginginformationoverlay_measureview.png" width="320px" alt="Ryan Peterson" itemprop="image" /></p>
<h2>The 'Spec Compare' screen</h2>
<p>I could see this being an incredibly useful tool for collaboration between development and design. Add a screenshot to your device and then select it from the Spec Compare screen. The selected screenshot will be displayed on top of the live app. You can then drag down to decrease alpha and compare the spec to the actual implementation.</p>
<p><strong>Update, May 26, 2017:</strong> <a href=""https://twitter.com/BalestraPatrick"">Patrick Balestra</a> reminded me that I left out an important step. You’ll need to include a value for the <a href="https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW17">NSPhotoLibraryUsageDescription</a> key in your Info.plist. Tapping the ‘Add’ button presents a <code class="language-plaintext highlighter-rouge">UIImagePickerController</code>, and doing so without setting this value will cause your app to crash.</p>
<p><img src="https://www.ryanipete.com/blog/assets/images/uidebugginginformationoverlay_speccomparepicker.png" width="320px" alt="Ryan Peterson" itemprop="image" /></p>
<p><img src="https://www.ryanipete.com/blog/assets/images/uidebugginginformationoverlay_speccompareoverlay.png" width="320px" alt="Ryan Peterson" itemprop="image" /></p>
<h1>Wrap-up</h1>
<p>I’ve only had a few days to play with this thing but am hoping to put it to use in our next beta. The console has a few rough edges, but it seems like a promising alternative to many of the open-source tools out there. If you have a chance to use it and notice anything that I missed, please feel free to reach out. I’ll update the post as I learn more.</p>Ryan Petersonhttps://www.ryanipete.comUpdate, December 9, 2017: This overlay still exists, but this post’s instructions don’t work on iOS 11 and later. In an update to his excellent book, Advanced Apple Debugging and Reverse Engineering, Derek Selander describes how to get the panel working in iOS 11. He’s generously posted the chapter for free here. While browsing UIKit’s private headers recently, I came across a class that I hadn’t seen before - UIDebuggingInformationOverlay. A Google search didn’t turn up much info, so figured I’d write a short description of what I’ve found. UIDebuggingInformationOverlay is a private UIWindow subclass created by Apple, presumably to help developers and designers debug Apple’s own iOS apps. When enabled, the window floats over your app’s content, like so: In this post, I’ll show you how to make it display. I’ll also summarize its features, at least as I understand them. How to show UIDebuggingInformationOverlay There are two steps needed to show UIDebuggingInformationOverlay in all its glory: Call [UIDebuggingInformationOverlay prepareDebuggingOverlay] - I’m not sure exactly what this method does, but the overlay will be empty if you don’t call it. Call [[UIDebuggingInformationOverlay overlay] toggleVisibility] - This shows the overlay window (assuming it’s not already visible). Because the class and its methods are private, you’ll need to jump through a few hoops to get the code to compile. One approach is to use the global ‘NSClassFromString’ and ‘NSSelectorFromString’ functions. In Swift, this approach looks something like: let overlayClass = NSClassFromString("UIDebuggingInformationOverlay") as? UIWindow.Type _ = overlayClass?.perform(NSSelectorFromString("prepareDebuggingOverlay")) let overlay = overlayClass?.perform(NSSelectorFromString("overlay")).takeUnretainedValue() as? UIWindow _ = overlay?.perform(NSSelectorFromString("toggleVisibility")) However you choose to do it, be sure that the code doesn’t make it into your App Store build, else you’re likely to get rejected. Update, May 26, 2017: Thanks to Bryce Pauken, who discovered that once you’ve called [UIDebuggingInformationOverlay prepareDebuggingOverlay], you can just tap the status bar with two fingers to show the console. No need to call toggleVisibility. Update, June 2, 2017: More from Bryce: I went through a disassembler (Hopper!) because I was curious about what prepareDebuggingOverlay did as well. Here’s part of the output. Even before parsing through it, statusBarWindow + numberOfTouchesRequired jumps out quickly enough: r14 = [[*_UIApp statusBarWindow] retain]; r15 = [UITapGestureRecognizer alloc]; rbx = [[UIDebuggingInformationOverlay overlay] retain]; r12 = [r15 initWithTarget:rbx action:@selector(_handleActivationGesture:)]; [rbx release]; [r12 setNumberOfTouchesRequired:0x2]; [r12 setNumberOfTapsRequired:0x1]; [r14 addGestureRecognizer:r12]; Another fun takeaway from Hopper — there actually is a spot in UIKit where this method is called: (-[UIApplication _runWithMainScene:transitionContext:completion:], seems to be called during app launch) which after some more digging, seems to enable the debug overlay if 1) CPIsInternalDevice() returns true, and 2) UserDefaults(suiteName: "com.apple.UIKit") has a value of true for “DebuggingOverlayEnabled”. No information there that makes this nicer to enable, but still fun food for thought :) What UIDebuggingInformationOverlay can do As you can see from the above screenshot, the overlay provides seven features. I’ll give a brief overview of the first six. I wasn’t able to get the ‘System Color Audit’ screen to show me anything, send me a message if you have better luck. The 'View Hierarchy' screen This screen shows what you’d probably expect; a list of views in the selected window. From here, you can inspect any view’s details, including its frame and instance variables. You can also switch between windows if you have more than one, or are just curious to see how a system window is built. The 'VC Hierarchy' screen You can probably predict what this screen does as well. It’s very similar to the ‘View Hierarchy’ screen, except that it shows the hierarchy of active view controllers. From here, you can inspect any view controller’s details, including its view. You can also see whether the view controller is presenting a modal or is itself being presented. The 'Ivar Explorer' screen This screen gives you access to the UIApplication instance’s variables. More importantly, any object variables can also be explored. This includes the app delegate which, depending on your app’s structure, might provide a handy entry point into your custom objects. The 'Measure' screen This is one of the cooler features of the overlay, in my opinion. It lets you measure dimensions (in points) of the screen’s elements. First, select whether you want to see measurements on the ‘Horizontal’ or ‘Vertical’ axis. Then drag your finger along the screen, using the magnified viewer inside the console to assist you. There are two modes: The default mode ignores view boundaries. As far as I can tell, this mode treats the screen as a single rasterized image, and uses changes in color as boundaries for potential measurements. For example, in the screenshot below, I am able to measure the distance between the end of a label’s text and the edge of the screen: “View mode”, on the other hand, displays the size of the subview in focus. Drag your finger over a view to see the selected axis’s dimension. In this screenshot, I’m measuring the height of the textfield at the top of the screen: The 'Spec Compare' screen I could see this being an incredibly useful tool for collaboration between development and design. Add a screenshot to your device and then select it from the Spec Compare screen. The selected screenshot will be displayed on top of the live app. You can then drag down to decrease alpha and compare the spec to the actual implementation. Update, May 26, 2017: Patrick Balestra reminded me that I left out an important step. You’ll need to include a value for the NSPhotoLibraryUsageDescription key in your Info.plist. Tapping the ‘Add’ button presents a UIImagePickerController, and doing so without setting this value will cause your app to crash. Wrap-up I’ve only had a few days to play with this thing but am hoping to put it to use in our next beta. The console has a few rough edges, but it seems like a promising alternative to many of the open-source tools out there. If you have a chance to use it and notice anything that I missed, please feel free to reach out. I’ll update the post as I learn more.My first LLDB command - Using Python to customize your debugging experience2017-03-21T00:00:00+00:002017-03-21T00:00:00+00:00https://www.ryanipete.com/blog/lldb/python/how_to_create_a_custom_lldb_command_pt_1<p>If you've ever used Xcode's console to debug, then you're probably familiar with at least a few LLDB commands. You can do things like print objects (using <code>po ...</code>), set breakpoints (using <code>breakpoint set ...</code>) or show the general purpose registers (using <code>register read</code>).</p>
<!-- exerpt_separator -->
<p>What you might not know is that you can create your own custom commands, and that these commands can do some powerful things. This post will describe how to create a basic LLDB command, and then will walk you through some of the setup needed to get the command showing up in Xcode.</p>
<p>Your command's guts will be written in Python. You won't be doing anything especially difficult, and you can probably feel your way through this post by copying the example code. If you'd like to learn the basics of Python before you begin, I recommend <a href="https://docs.python.org/3/tutorial/">the official Python tutorial</a>.</p>
<p>At the end of this post, you’ll be able to enter your new command at the LLDB prompt and see the message being printed by your Python function:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(lldb) hello
world!
</code></pre></div></div>
<h1 id="step1createyourfunction">Step 1: Create your function</h1>
<p>In this step, You'll write your Python function.</p>
<p>Open your text editor of choice and create a new Python file. Name it <strong>my_commands.py</strong> and save it somewhere convenient (you’ll tell LLDB exactly where to find it in Step 2).</p>
<p>Inside <strong>my_commands.py</strong>, add a function named <code><span class="functionname">printworld</span></code>. This is the function that LLDB will call when you run your command. Be sure that your function takes four parameters. You won't use them here, but your command will fail if they're missing. Inside your function, print a single line of text:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">printworld</span><span class="p">(</span><span class="n">debugger</span><span class="p">,</span> <span class="n">command</span><span class="p">,</span> <span class="n">result</span><span class="p">,</span> <span class="n">internal_dict</span><span class="p">):</span>
<span class="k">print</span> <span class="err">“</span><span class="n">world</span><span class="err">!”</span>
</code></pre></div></div>
<h1 id="step2importyourscript">Step 2: Import your script</h1>
<p>In this step, you'll tell LLDB where to find your Python file.</p>
<p>Enter the LLDB command line, either by running and then pausing one of your projects in Xcode, or by running <code>lldb</code> in your terminal. Either way, you should see a prompt like this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(lldb)
</code></pre></div></div>
<p>You load new <a href="https://docs.python.org/3/tutorial/modules.html">Python modules</a> (i.e. Python files) into LLDB using the <code class="command">command script import</code> command (confusing naming, I know). This command takes a single argument - the path to the module you'd like to import. I saved my file to my home directory (<code>~/my_commands.py</code>), so my command looks like this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(lldb) command script import ~/my_commands.py
</code></pre></div></div>
<p>After running this command, LLDB will know where your file is saved. However, you still need a way to call the function inside the file.</p>
<h1 id="step3addyourcommand">Step 3: Add your command</h1>
<p>Here’s where you name your LLDB command and map it to your Python function. You do this using the <code>command script add</code> command. I'll show you the full command first, and then will describe the parts:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(lldb) command script add -f my_commands.printworld hello
</code></pre></div></div>
<ul>
<li>The <code>-f</code> parameter indicates that you want to bind a Python function to your command.</li>
<li> <code>my_commands.printworld</code> is the full name of your Python function. You must prefix the module name (<code>my_commands</code>) to the function name (<code>printworld</code>). LLDB doesn't warn you if the function name you provide doesn't exist. If you see a message like "error: unable to execute script function" when you try to run your command, double-check your command name for typos.</li>
<li><code>hello</code> is the name of your new command.</li>
</ul>
<p>At this point, you've got a fully-functioning command. Try it out, and you should see the text printed by the Python function:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(lldb) hello
world!
</code></pre></div></div>
<p>If you stop now, you'll need to repeat steps 2 and 3 every time you launch LLDB. To automatically load the script when Xcode launches, you've got one more step to complete.</p>
<h1 id="step4addtolldbinit">Step 4: Automatically load your script when Xcode launches</h1>
<p>In this step, you'll configure LLDB to load your command every time you start a new session. You do this by taking advantage of the .lldbinit file.</p>
<p>.lldbinit is the file that LLDB looks for and loads each time a new session is started. Create this file in your home directory (or open this file now). Somewhere in the file, add the <code>command script import</code> and <code>command script add</code> commands from steps 2 and 3:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>command script import ~/my_commands.py
command script add -f my_commands.printworld hello
</code></pre></div></div>
<p>Now, when you start a new LLDB session, your <code>hello</code> command will be available right away.</p>
<h1>Conclusion</h1>
<p>This is a trivial example, but LLDB provides a Python library that gives you a ton of functionality. In Part 2, I'll use some of this functionality to fill out my new command.</p>Ryan Petersonhttps://www.ryanipete.comIf you've ever used Xcode's console to debug, then you're probably familiar with at least a few LLDB commands. You can do things like print objects (using po ...), set breakpoints (using breakpoint set ...) or show the general purpose registers (using register read).