| <!DOCTYPE HTML> |
| <html lang="en" class="light sidebar-visible" dir="ltr"> |
| <head> |
| <!-- Book generated using mdBook --> |
| <meta charset="UTF-8"> |
| <title>LLDB - Python Providers - Rust Compiler Development Guide</title> |
| |
| |
| <!-- Custom HTML head --> |
| |
| <meta name="description" content="A guide to developing the Rust compiler (rustc)"> |
| <meta name="viewport" content="width=device-width, initial-scale=1"> |
| <meta name="theme-color" content="#ffffff"> |
| |
| <link rel="icon" href="../favicon-de23e50b.svg"> |
| <link rel="shortcut icon" href="../favicon-8114d1fc.png"> |
| <link rel="stylesheet" href="../css/variables-8adf115d.css"> |
| <link rel="stylesheet" href="../css/general-2459343d.css"> |
| <link rel="stylesheet" href="../css/chrome-ae938929.css"> |
| <link rel="stylesheet" href="../css/print-9e4910d8.css" media="print"> |
| |
| <!-- Fonts --> |
| <link rel="stylesheet" href="../fonts/fonts-9644e21d.css"> |
| |
| <!-- Highlight.js Stylesheets --> |
| <link rel="stylesheet" id="mdbook-highlight-css" href="../highlight-493f70e1.css"> |
| <link rel="stylesheet" id="mdbook-tomorrow-night-css" href="../tomorrow-night-4c0ae647.css"> |
| <link rel="stylesheet" id="mdbook-ayu-highlight-css" href="../ayu-highlight-3fdfc3ac.css"> |
| |
| <!-- Custom theme stylesheets --> |
| |
| |
| <!-- Provide site root and default themes to javascript --> |
| <script> |
| const path_to_root = "../"; |
| const default_light_theme = "light"; |
| const default_dark_theme = "navy"; |
| window.path_to_searchindex_js = "../searchindex-1dcc4ecd.js"; |
| </script> |
| <!-- Start loading toc.js asap --> |
| <script src="../toc-39e8ee02.js"></script> |
| </head> |
| <body> |
| <div id="mdbook-help-container"> |
| <div id="mdbook-help-popup"> |
| <h2 class="mdbook-help-title">Keyboard shortcuts</h2> |
| <div> |
| <p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p> |
| <p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p> |
| <p>Press <kbd>?</kbd> to show this help</p> |
| <p>Press <kbd>Esc</kbd> to hide this help</p> |
| </div> |
| </div> |
| </div> |
| <div id="mdbook-body-container"> |
| <!-- Work around some values being stored in localStorage wrapped in quotes --> |
| <script> |
| try { |
| let theme = localStorage.getItem('mdbook-theme'); |
| let sidebar = localStorage.getItem('mdbook-sidebar'); |
| |
| if (theme.startsWith('"') && theme.endsWith('"')) { |
| localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1)); |
| } |
| |
| if (sidebar.startsWith('"') && sidebar.endsWith('"')) { |
| localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1)); |
| } |
| } catch (e) { } |
| </script> |
| |
| <!-- Set the theme before any content is loaded, prevents flash --> |
| <script> |
| const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme; |
| let theme; |
| try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { } |
| if (theme === null || theme === undefined) { theme = default_theme; } |
| const html = document.documentElement; |
| html.classList.remove('light') |
| html.classList.add(theme); |
| html.classList.add("js"); |
| </script> |
| |
| <input type="checkbox" id="mdbook-sidebar-toggle-anchor" class="hidden"> |
| |
| <!-- Hide / unhide sidebar before it is displayed --> |
| <script> |
| let sidebar = null; |
| const sidebar_toggle = document.getElementById("mdbook-sidebar-toggle-anchor"); |
| if (document.body.clientWidth >= 1080) { |
| try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { } |
| sidebar = sidebar || 'visible'; |
| } else { |
| sidebar = 'hidden'; |
| sidebar_toggle.checked = false; |
| } |
| if (sidebar === 'visible') { |
| sidebar_toggle.checked = true; |
| } else { |
| html.classList.remove('sidebar-visible'); |
| } |
| </script> |
| |
| <nav id="mdbook-sidebar" class="sidebar" aria-label="Table of contents"> |
| <!-- populated by js --> |
| <mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox> |
| <noscript> |
| <iframe class="sidebar-iframe-outer" src="../toc.html"></iframe> |
| </noscript> |
| <div id="mdbook-sidebar-resize-handle" class="sidebar-resize-handle"> |
| <div class="sidebar-resize-indicator"></div> |
| </div> |
| </nav> |
| |
| <div id="mdbook-page-wrapper" class="page-wrapper"> |
| |
| <div class="page"> |
| <div id="mdbook-menu-bar-hover-placeholder"></div> |
| <div id="mdbook-menu-bar" class="menu-bar sticky"> |
| <div class="left-buttons"> |
| <label id="mdbook-sidebar-toggle" class="icon-button" for="mdbook-sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="mdbook-sidebar"> |
| <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"/></svg></span> |
| </label> |
| <button id="mdbook-theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="mdbook-theme-list"> |
| <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M371.3 367.1c27.3-3.9 51.9-19.4 67.2-42.9L600.2 74.1c12.6-19.5 9.4-45.3-7.6-61.2S549.7-4.4 531.1 9.6L294.4 187.2c-24 18-38.2 46.1-38.4 76.1L371.3 367.1zm-19.6 25.4l-116-104.4C175.9 290.3 128 339.6 128 400c0 3.9 .2 7.8 .6 11.6c1.8 17.5-10.2 36.4-27.8 36.4H96c-17.7 0-32 14.3-32 32s14.3 32 32 32H240c61.9 0 112-50.1 112-112c0-2.5-.1-5-.2-7.5z"/></svg></span> |
| </button> |
| <ul id="mdbook-theme-list" class="theme-popup" aria-label="Themes" role="menu"> |
| <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-default_theme">Auto</button></li> |
| <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-light">Light</button></li> |
| <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-rust">Rust</button></li> |
| <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-coal">Coal</button></li> |
| <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-navy">Navy</button></li> |
| <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-ayu">Ayu</button></li> |
| </ul> |
| <button id="mdbook-search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="mdbook-searchbar"> |
| <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352c79.5 0 144-64.5 144-144s-64.5-144-144-144S64 128.5 64 208s64.5 144 144 144z"/></svg></span> |
| </button> |
| </div> |
| |
| <h1 class="menu-title">Rust Compiler Development Guide</h1> |
| |
| <div class="right-buttons"> |
| <a href="../print.html" title="Print this book" aria-label="Print this book"> |
| <span class=fa-svg id="print-button"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M128 0C92.7 0 64 28.7 64 64v96h64V64H354.7L384 93.3V160h64V93.3c0-17-6.7-33.3-18.7-45.3L400 18.7C388 6.7 371.7 0 354.7 0H128zM384 352v32 64H128V384 368 352H384zm64 32h32c17.7 0 32-14.3 32-32V256c0-35.3-28.7-64-64-64H64c-35.3 0-64 28.7-64 64v96c0 17.7 14.3 32 32 32H64v64c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V384zm-16-88c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24z"/></svg></span> |
| </a> |
| <a href="https://github.com/rust-lang/rustc-dev-guide" title="Git repository" aria-label="Git repository"> |
| <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg></span> |
| </a> |
| <a href="https://github.com/rust-lang/rustc-dev-guide/edit/main/src/debuginfo/lldb-visualizers.md" title="Suggest an edit" aria-label="Suggest an edit" rel="edit"> |
| <span class=fa-svg id="git-edit-button"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M421.7 220.3l-11.3 11.3-22.6 22.6-205 205c-6.6 6.6-14.8 11.5-23.8 14.1L30.8 511c-8.4 2.5-17.5 .2-23.7-6.1S-1.5 489.7 1 481.2L38.7 353.1c2.6-9 7.5-17.2 14.1-23.8l205-205 22.6-22.6 11.3-11.3 33.9 33.9 62.1 62.1 33.9 33.9zM96 353.9l-9.3 9.3c-.9 .9-1.6 2.1-2 3.4l-25.3 86 86-25.3c1.3-.4 2.5-1.1 3.4-2l9.3-9.3H112c-8.8 0-16-7.2-16-16V353.9zM453.3 19.3l39.4 39.4c25 25 25 65.5 0 90.5l-14.5 14.5-22.6 22.6-11.3 11.3-33.9-33.9-62.1-62.1L314.3 67.7l11.3-11.3 22.6-22.6 14.5-14.5c25-25 65.5-25 90.5 0z"/></svg></span> |
| </a> |
| |
| </div> |
| </div> |
| |
| <div id="mdbook-search-wrapper" class="hidden"> |
| <form id="mdbook-searchbar-outer" class="searchbar-outer"> |
| <div class="search-wrapper"> |
| <input type="search" id="mdbook-searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="mdbook-searchresults-outer" aria-describedby="searchresults-header"> |
| <div class="spinner-wrapper"> |
| <span class=fa-svg id="fa-spin"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M304 48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zm0 416c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM48 304c26.5 0 48-21.5 48-48s-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48zm464-48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM142.9 437c18.7-18.7 18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zm0-294.2c18.7-18.7 18.7-49.1 0-67.9S93.7 56.2 75 75s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zM369.1 437c18.7 18.7 49.1 18.7 67.9 0s18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9z"/></svg></span> |
| </div> |
| </div> |
| </form> |
| <div id="mdbook-searchresults-outer" class="searchresults-outer hidden"> |
| <div id="mdbook-searchresults-header" class="searchresults-header"></div> |
| <ul id="mdbook-searchresults"> |
| </ul> |
| </div> |
| </div> |
| |
| <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM --> |
| <script> |
| document.getElementById('mdbook-sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible'); |
| document.getElementById('mdbook-sidebar').setAttribute('aria-hidden', sidebar !== 'visible'); |
| Array.from(document.querySelectorAll('#mdbook-sidebar a')).forEach(function(link) { |
| link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1); |
| }); |
| </script> |
| |
| <div id="mdbook-content" class="content"> |
| <main> |
| <h1 id="lldb---python-providers"><a class="header" href="#lldb---python-providers">LLDB - Python Providers</a></h1> |
| <blockquote> |
| <p>NOTE: LLDB’s C++<->Python FFI expects a version of python designated at the time LLDB was |
| compiled. LLDB is careful to correspond this version to the minimum in typical Linux and macOS |
| distributions, but on Windows there is no easy solution. If you recieve an import error regarding |
| <code>_lldb</code> not existing, a mismatched Python version is likely the cause.</p> |
| <p>LLDB is considering solutions this issue. For updates, see |
| <a href="https://discourse.llvm.org/t/a-minimal-python-install-for-lldb/88658">this discussion</a> and <a href="https://github.com/llvm/llvm-project/issues/167001">this github issue</a></p> |
| </blockquote> |
| <blockquote> |
| <p>NOTE: Currently (Nov 2025), LLDB’s minimum supported Python version is 3.8 with plans to update it to |
| 3.9 or 3.10 depending on several outside factors. Scripts should ideally be written with only the |
| features available in the minimum supported Python version. Please see <a href="https://discourse.llvm.org/t/rfc-upgrading-llvm-s-minimum-required-python-version/88605/">this discussion</a> for |
| more info.</p> |
| </blockquote> |
| <blockquote> |
| <p>NOTE: The path to LLDB’s python package can be located via the CLI command <code>lldb -P</code></p> |
| </blockquote> |
| <p>LLDB provides 3 mechanisms for customizing output:</p> |
| <ul> |
| <li>Formats</li> |
| <li>Synthetic providers</li> |
| <li>Summary providers</li> |
| </ul> |
| <h2 id="formats"><a class="header" href="#formats">Formats</a></h2> |
| <p>The official documentation is <a href="https://lldb.llvm.org/use/variable.html#type-format">here</a>. In short, |
| formats allow one to set the default print format for primitive types (e.g. print <code>25u8</code> as decimal |
| <code>25</code>, hex <code>0x19</code>, or binary <code>00011001</code>).</p> |
| <p>Rust will almost always need to override <code>unsigned char</code>, <code>signed char</code>, <code>char</code>, <code>u8</code>, and <code>i8</code>, to |
| (unsigned) decimal format.</p> |
| <h2 id="synthetic-providers"><a class="header" href="#synthetic-providers">Synthetic Providers</a></h2> |
| <p>The official documentation is <a href="https://lldb.llvm.org/use/variable.html#synthetic-children">here</a>, |
| but some information is vague, outdated, or entirely missing.</p> |
| <p>Nearly all interaction the user has with variables will be through LLDB’s |
| <a href="https://lldb.llvm.org/python_api/lldb.SBValue.html"><code>SBValue</code> objects</a> which are used both in the Python API, and internally via LLDB’s |
| plugins and CLI.</p> |
| <p>A Synthetic Provider is a Python class, written with a specific interface, that is associated with |
| one or more Rust types. The Synthetic Provider wraps <code>SBValue</code> objects and LLDB will call our |
| class’s functions when inspecting the variable.</p> |
| <p>The wrapped value is still an <code>SBValue</code>, but when calling e.g. <code>SBValue.GetChildAtIndex</code>, it will |
| internally call <code>SyntheticProvider.get_child_at_index</code>. You can check if a value has a synthetic |
| provider via <code>SBValue.IsSynthetic()</code>, and which synthetic it is via <code>SBValue.GetTypeSynthetic()</code>. If |
| you want to interact with the underlying non-synthetic value, you can call |
| <code>SBValue.GetNonSyntheticValue()</code>.</p> |
| <p>The expected interface is as follows:</p> |
| <pre><code class="language-python">class SyntheticProvider: |
| def __init__(self, valobj: SBValue, _lldb_internal): ... |
| |
| # optional |
| def update(self) -> bool: ... |
| |
| # optional |
| def has_children(self) -> bool: ... |
| |
| # optional |
| def num_children(self, max_children: int) -> int: ... |
| |
| def get_child_index(self, name: str) -> int: ... |
| |
| def get_child_at_index(self, index: int) -> SBValue: ... |
| |
| # optional |
| def get_type_name(self) -> str: ... |
| |
| # optional |
| def get_value(self) -> SBValue: ... |
| </code></pre> |
| <p>Below are explanations of the methods, their quirks, and how they should generally be used. If a |
| method overrides an <code>SBValue</code> method, that method will be listed.</p> |
| <h3 id="__init__"><a class="header" href="#__init__"><code>__init__</code></a></h3> |
| <p>This function is called once per object, and must store the <code>valobj</code> in the python class so that it |
| is accessible elsewhere. Very little else should be done here.</p> |
| <h3 id="optional-update"><a class="header" href="#optional-update">(optional) <code>update</code></a></h3> |
| <p>This function is called prior to LLDB interacting with a variable, but after <code>__init__</code>. LLDB tracks |
| whether <code>update</code> has already been called. If it has been, and if it is not possible for the variable |
| to have changed (e.g. inspecting the same variable a second time without stepping), it will omit the |
| call to <code>update</code>.</p> |
| <p>This function has 2 purposes:</p> |
| <ul> |
| <li>Store/update any information that may have changed since the last time <code>update</code> was run</li> |
| <li>Inform LLDB if there were changes to the children such that it should flush the child cache.</li> |
| </ul> |
| <p>Typical operations include storing the heap pointer, length, capacity, and element type of a <code>Vec</code>, |
| determining an enum variable’s variant, or checking which slots of a <code>HashMap</code> are occupied.</p> |
| <p>The bool returned from this function is somewhat complicated, see: |
| <a href="#update-caching"><code>update</code> caching</a> below for more info. When in doubt, return <code>False</code>/<code>None</code>. |
| Currently (Nov 2025), none of the visualizers return <code>True</code>, but that may change as the debug info |
| test suite is improved.</p> |
| <h4 id="update-caching"><a class="header" href="#update-caching"><code>update</code> caching</a></h4> |
| <p>LLDB attempts to cache values when possible, including child values. This cache is effectively the |
| number of child objects, and the addresses of the underlying debugee memory that the child object |
| represents. By returning <code>True</code>, you indicate to LLDB that the number of children and the addresses |
| of those children have not changed since the last time <code>update</code> was run, meaning it can reuse the |
| cached children.</p> |
| <p><strong>Returning <code>True</code> in the wrong circumstances will result in the debugger outputting incorrect |
| information</strong>.</p> |
| <p>Returning <code>False</code> indicates that there have been changes, the cache will be flushed, and the |
| children will be fetched from scratch. It is the safer option if you are unsure.</p> |
| <p>The only relationship that matters is parent-to-child. Grandchildren depend on the <code>update</code> function |
| of their direct parent, not that of the grandparent.</p> |
| <p>It is important to view the child cache as pointers-to-memory. For example, if a slice’s <code>data_ptr</code> |
| value and <code>length</code> have not changed, returning <code>True</code> is appropriate. Even if the slice is mutable |
| and elements of it are overwritten (e.g. <code>slice[0] = 15</code>), because the child cache consists of |
| <em>pointers</em>, they will reflect the new data at that memory location.</p> |
| <p>Conversely, if <code>data_ptr</code> has changed, that means it is pointing to a new location in memory, the |
| child pointers are invalid, and the cache must be flushed. If the <code>length</code> has changed, we need to |
| flush the cache to reflect the new number of children. If <code>length</code> has changed but <code>data_ptr</code> has |
| not, it is possible to store the old children in the <code>SyntheticProvider</code> itself (e.g. |
| <code>list[SBValue]</code>) and dole those out rather than generating them from scratch, only creating new |
| children if they do not already exist in the <code>SyntheticProvider</code>’s list.</p> |
| <p>For further clarification, see <a href="https://discourse.llvm.org/t/when-is-it-safe-to-cache-syntheticprovider-update/88608">this discussion</a></p> |
| <blockquote> |
| <p>NOTE: when testing the caching behavior, do not rely on LLDB’s heuristic to persist variables when |
| stepping. Instead, store the variable in a python object (e.g. <code>v = lldb.frame.var("var_name")</code>), |
| step forward, and then inspect the stored variable.</p> |
| </blockquote> |
| <h3 id="optional-has_children"><a class="header" href="#optional-has_children">(optional) <code>has_children</code></a></h3> |
| <blockquote> |
| <p>Overrides <code>SBValue.MightHaveChildren</code></p> |
| </blockquote> |
| <p>This is a shortcut used by LLDB to check if the value has children <em>at all</em>, without doing |
| potentially expensive computations to determine how many children there are (e.g. linked list). |
| Often, this will be a one-liner of <code>return True</code>/<code>return False</code> or |
| <code>return self.valobj.MightHaveChildren()</code>.</p> |
| <h3 id="optional-num_children"><a class="header" href="#optional-num_children">(optional) <code>num_children</code></a></h3> |
| <blockquote> |
| <p>Overrides <code>SBValue.GetNumChildren</code></p> |
| </blockquote> |
| <p>Returns the total number of children that LLDB should try to access when printing the type. This |
| number <strong>does not</strong> need to match to total number of synthetic children.</p> |
| <p>The <code>max_children</code> argument can be returned if calculating the number of children can be expensive |
| (e.g. linked list). If this is not a consideration, <code>max_children</code> can be omitted from the function |
| signature.</p> |
| <p>Additionally, fields can be intentionally “hidden” from LLDB while still being accessible to the |
| user. For example, one might want a <code>vec![1, 2, 3]</code> to display only its elements, but still have the |
| <code>len</code> and <code>capacity</code> values accessible on request. By returning <code>3</code> from <code>num_children</code>, one can |
| restrict LLDB to only displaying <code>[1, 2, 3]</code>, while users can still directly access <code>v.len</code> and |
| <code>v.capacity</code>. See: <a href="#example-provider-vect">Example Provider: Vec<T></a> to see an implementation of |
| this.</p> |
| <h3 id="get_child_index"><a class="header" href="#get_child_index"><code>get_child_index</code></a></h3> |
| <blockquote> |
| <p>Overrides <code>SBValue.GetIndexOfChildWithName</code></p> |
| <p>Affects <code>SBValue.GetChildMemberWithName</code></p> |
| </blockquote> |
| <p>Given a name, returns the index that the child should be accessed at. It is expected that the return |
| value of this function is passed directly to <code>get_child_at_index</code>. As with <code>num_children</code>, the |
| values returned here <em>can</em> be arbitrary, so long as they are properly coordinated with |
| <code>get_child_at_index</code>.</p> |
| <p>One special value is <code>$$dereference$$</code>. Accounting for this pseudo-field will allow LLDB to use the |
| <code>SBValue</code> returned from <code>get_child_at_index</code> as the result of a dereference via LLDB’s expression |
| parser (e.g. <code>*val</code> and <code>val->field</code>)</p> |
| <h3 id="get_child_at_index"><a class="header" href="#get_child_at_index"><code>get_child_at_index</code></a></h3> |
| <blockquote> |
| <p>Overrides <code>SBValue.GetChildAtIndex</code></p> |
| </blockquote> |
| <p>Given an index, returns a child <code>SBValue</code>. Often these are generated via |
| <code>SBValue.CreateValueFromAddress</code>, but less commonly <code>SBValue.CreateChildAtOffset</code>, |
| <code>SBValue.CreateValueFromExpression</code>, and <code>SBValue.CreateValueFromData</code>. These functions can be a |
| little finicky, so you may need to fiddle with them to get the output you want.</p> |
| <p>In some cases, <code>SBValue.Clone</code> is appropriate. It creates a new child that is an exact copy of an |
| existing child, but with a new name. This is useful for cases like tuples, which have field names of |
| the style <code>__0</code>, <code>__1</code>, … when we would prefer they were named <code>0</code>, <code>1</code>, …</p> |
| <p>Small alterations can be made to the resulting child before it is returned. This is useful for |
| <code>&str</code>/<code>String</code>, where we would prefer if the children were displayed as |
| <code>lldb.eFormatBytesWithASCII</code> rather than just as a decimal value.</p> |
| <h3 id="optional-get_type_name"><a class="header" href="#optional-get_type_name">(optional) <code>get_type_name</code></a></h3> |
| <blockquote> |
| <p>Overrides <code>SBValue.GetDisplayTypeName</code></p> |
| </blockquote> |
| <p>Overrides the displayed name of a type. For a synthetic <code>SBValue</code> whose type name is overridden, the |
| original type name can still be retrieved via <code>SBValue.GetTypeName()</code> and |
| <code>SBValue.GetType().GetName()</code></p> |
| <p>This can be helpful in shortening the name of common standard library types (e.g. |
| <code>std::collections::hash::map::HashMap<K, V, std::hash::random::RandomState></code> -> <code>HashMap<K, V></code>), or |
| in normalizing MSVC type names (e.g. <code>ref$<str$></code> -> <code>&str</code>).</p> |
| <p>The string manipulation can be a little tricky, especially on MSVC where we cannot conveniently |
| access the generic parameters of the type.</p> |
| <h3 id="optional-get_value"><a class="header" href="#optional-get_value">(optional) <code>get_value</code></a></h3> |
| <blockquote> |
| <p>Overrides <code>SBValue.GetValue()</code>, <code>SBValue.GetValueAsUnsigned()</code>, <code>SBValue.GetValueAsSigned()</code>, |
| <code>SBValue.GetValueAsAddress()</code>,</p> |
| </blockquote> |
| <p>The <code>SBValue</code> returned is expected to be a primitive type or pointer, and is treated as the value of |
| the variable in expressions.</p> |
| <blockquote> |
| <p>IMPORTANT: The <code>SBValue</code> returned <strong>must be stored in the <code>SyntheticProvider</code></strong>. There is |
| currently (Nov 2025) a bug where if the <code>SBValue</code> is acquired within <code>get_value</code> and not stored |
| anywhere, Python will segfault when LLDB attempts to access the value.</p> |
| </blockquote> |
| <h2 id="summary-providers"><a class="header" href="#summary-providers">Summary Providers</a></h2> |
| <p>Summary providers are python functions of the following form:</p> |
| <pre><code class="language-python">def SummaryProvider(valobj: SBValue, _lldb_internal) -> str: ... |
| </code></pre> |
| <p>Where the returned string is passed verbatim to the user. If the returned value isn’t a string, it |
| is naively convered to a string (e.g. <code>return None</code> prints <code>"None"</code>, not an empty string).</p> |
| <p>If the <code>SBValue</code> passed in is of a type that has a Synthetic Provider, <code>valobj.IsSynthetic()</code> will |
| return <code>True</code>, and the synthetic’s corresponding functions will be used. If this is undesirable, the |
| original value can be retrieved via <code>valobj.GetNonSyntheticValue()</code>. This can be helpful in cases |
| like <code>String</code>, where individually calling <code>GetChildAtIndex</code> in a loop is much slower than accessing |
| the heap pointer, reading the whole byte array directly from the debugee’s memory, and using |
| Python’s <code>bytes.decode()</code>.</p> |
| <h3 id="instance-summaries"><a class="header" href="#instance-summaries">Instance Summaries</a></h3> |
| <p>Regular <code>SummaryProvider</code> functions take an opaque <code>SBValue</code>. That <code>SBValue</code> will reflect the type’s |
| <code>SyntheticProvider</code> if one exists, but we cannot access the <code>SyntheticProvider</code> instance itself, or |
| any of its internal implementation details. This is deterimental in cases where we need some of |
| those internal details to help complete the summary. Currently (Nov 2025), in the synthetic we just |
| run the non-synthetic value through the synthetic provider |
| (<code>synth = SyntheticProvider(valobj.GetNonSyntheticValue(), _dict)</code>), but this is obviously |
| suboptimal and there are plans to use the method outlined below.</p> |
| <p>Instead, we can leverage the Python module’s state to allow for instance summaries. Prior art for |
| this technique exists in the <a href="https://github.com/vadimcn/codelldb/blob/cf9574977b80e29c6de2c44d12f1071a53a54caf/formatters/rust.py#L110">old CodeLLDB Rust visualizer scripts</a>.</p> |
| <p>In short: every Synthetic Provider’s <code>__init__</code> function stores a unique ID and a weak reference to |
| <code>self</code> in a global dictionary. The Synthetic Provider class also implements a <code>get_summary</code> |
| function. The type’s <code>SummaryProvider</code> is a function that looks up the unique ID in this dictionary, |
| then calls a <code>get_summary</code> on the instance it retrieves.</p> |
| <pre><code class="language-python">import weakref |
| |
| SYNTH_BY_ID = weakref.WeakValueDictionary() |
| |
| class SyntheticProvider: |
| valobj: SBValue |
| |
| # slots requires opting-in to __weakref__ |
| __slots__ = ("valobj", "__weakref__") |
| |
| def __init__(valobj: SBValue, _dict): |
| SYNTH_BY_ID[valobj.GetID()] = self |
| self.valobj = valobj |
| |
| def get_summary(self) -> str: |
| ... |
| |
| def InstanceSummaryProvider(valobj: SBValue, _dict) -> str: |
| # GetNonSyntheticValue should never fail as InstanceSummaryProvider implies an instance of a |
| # `SyntheticProvider`. No non-synthetic types should ever have this summary assigned to them |
| # We use GetNonSyntheticValue because the synthetic vaobj has its own unique ID |
| return SYNTH_BY_ID[valobj.GetNonSyntheticValue().GetID()].get_summary() |
| </code></pre> |
| <p>For example, one might use this for the Enum synthetic provider. The summary would like to access |
| the variant name, but there isn’t a convenient way to reflect this via the type name or child-values |
| of the synthetic. By implementing an instance summary, we can retrieve the variant name via |
| <code>self.variant.GetTypeName()</code> and some string manipulation.</p> |
| <h1 id="writing-visualizer-scripts"><a class="header" href="#writing-visualizer-scripts">Writing Visualizer Scripts</a></h1> |
| <blockquote> |
| <p>IMPORTANT: Unlike GDB and CDB, LLDB can debug executables with either DWARF or PDB debug info. |
| Visualizers must be written to account for both formats whenever possible. See: |
| <a href="./rust-codegen.html#dwarf-vs-pdb">rust-codegen</a> for an overview of the differences</p> |
| </blockquote> |
| <p>Scripts are injected into LLDB via the CLI command <code>command script import <path-to-script>.py</code>. Once |
| injected, classes and functions can be added to the synthetic/summary pool with <code>type synthetic add</code> |
| and <code>type summary add</code> respectively. The summaries and synthetics can be associated with a |
| “category”, which is typically named after the language the providers are intended for. The category |
| we use will be called <code>Rust</code>.</p> |
| <blockquote> |
| <p>TIP: all LLDB commands can be prefixed with <code>help</code> (e.g. <code>help type synthetic add</code>) for a brief |
| description, list of arguments, and examples.</p> |
| </blockquote> |
| <p>Currently (Nov 2025) we use <code>command source ...</code>, which executes a series of CLI commands from the |
| file <a href="https://github.com/rust-lang/rust/blob/main/src/etc/lldb_commands"><code>lldb_commands</code></a> to add |
| providers. This file is somewhat unwieldy, and will soon be supplanted by the Python API equivalent |
| outlined below.</p> |
| <h2 id="__lldb_init_module"><a class="header" href="#__lldb_init_module"><code>__lldb_init_module</code></a></h2> |
| <p>This is an optional function of the form:</p> |
| <pre><code class="language-python">def __lldb_init_module(debugger: SBDebugger, _lldb_internal) -> None: ... |
| </code></pre> |
| <p>This function is called at the end of <code>command script import ...</code>, but before control returns back |
| to the CLI. It allows the script to initialize its own state.</p> |
| <p>Crucially, it is passed a reference to the debugger itself. This allows us to create the <code>Rust</code> |
| category and add providers to it. It can also allow us to conditionally change which providers we |
| use depending on what version of LLDB the script detects. This is vital for backwards compatibility |
| once we begin using recognizer functions, as recognizers were added in lldb 19.0.</p> |
| <h2 id="visualizer-resolution"><a class="header" href="#visualizer-resolution">Visualizer Resolution</a></h2> |
| <p>The order that visualizers resolve in is listed <a href="https://lldb.llvm.org/use/variable.html#finding-formatters-101">here</a>. In short:</p> |
| <ul> |
| <li>If there is an exact match (non-regex name, recognizer function, or type already matched to |
| provider), use that</li> |
| <li>If the object is a pointer/reference, try to use the dereferenced type’s formatter</li> |
| <li>If the object is a typedef, check the underlying type for a formatter</li> |
| <li>If none of the above work, iterate through the regex type matchers</li> |
| </ul> |
| <p>Within each of those steps, <strong>iteration is done backwards</strong> to allow new commands to “override” old |
| commands. This is important for cases like <code>Box<str></code> vs <code>Box<T></code>, were we want a specialized |
| synthetic for the former, but a more generalized synthetic for the latter.</p> |
| <h2 id="minutiae"><a class="header" href="#minutiae">Minutiae</a></h2> |
| <p>LLDB’s API is very powerful, but there are some “gotchas” and unintuitive behavior, some of which |
| will be outlined below. The python implementation can be viewed at the path returned by the CLI |
| command <code>lldb -P</code> in <code>lldb\__init__.py</code>. In addition to the |
| <a href="https://github.com/llvm/llvm-project/tree/main/lldb/examples/synthetic">examples in the lldb repo</a>, there are also <a href="https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/Language/CPlusPlus">C++ visualizers</a> that can |
| be used as a reference (e.g. <a href="https://github.com/llvm/llvm-project/blob/main/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp">LibCxxVector, the equivalent to <code>Vec<T></code></a>). While C++’s |
| visualizers are written in C++ and have access to LLDB’s internals, the API and general practices |
| are very similar.</p> |
| <h3 id="sbvalue"><a class="header" href="#sbvalue"><code>SBValue</code></a></h3> |
| <ul> |
| <li>Pointer/reference <code>SBValue</code>s will effectively “auto-deref” in some cases, acting as if the |
| children of the pointed-to-object are its own children.</li> |
| <li>The non-function fields are typically <a href="https://docs.python.org/3/library/functions.html#property"><code>property()</code></a> fields that point directly to the |
| function anyway (e.g. <code>SBValue.type = property(GetType, None)</code>). Accessing through these shorthands |
| is a bit slower to access than just calling the function directly, so they should be avoided. Some |
| of the properties return special objects with special properties (e.g. <code>SBValue.member</code> returns an |
| object that acts like <code>dict[str, SBValue]</code> to access children). Internally, many of these special |
| objects just allocate a new class instance and call the function on the <code>SBValue</code> anyway, resulting |
| in additional performance loss (e.g. <code>SBValue.member</code> internally just implements <code>__getitem__</code> which |
| is the one-liner <code>return self.valobj.GetChildMemberWithName(name)</code>)</li> |
| <li><code>SBValue.GetID</code> returns a unique <code>int</code> for each value for the duration of the debug session. |
| Synthetic <code>SBValue</code>’s have a different ID than their underlying <code>SBValue</code>. The underlying ID can be |
| retrieved via <code>SBValue.GetNonSyntheticValue().GetID()</code>.</li> |
| <li>When manually calculating an address, <code>SBValue.GetValueAsAddress</code> should be preferred over |
| <code>SBValue.GetValueAsUnsigned</code> due to <a href="https://lldb.llvm.org/python_api/lldb.SBValue.html#lldb.SBValue.GetValueAsAddress">target-specific behavior</a></li> |
| <li>Getting a string representation of an <code>SBValue</code> can be tricky because <code>GetSummary</code> requires a |
| summary provider and <code>GetValue</code> requires the type be representable by a primitive. In almost all |
| cases where neither of those conditions are met, the type is a user defined struct that can be |
| passed through <code>StructSummaryProvider</code>.</li> |
| </ul> |
| <h3 id="sbtype"><a class="header" href="#sbtype"><code>SBType</code></a></h3> |
| <ul> |
| <li>“Aggregate type” means a non-primitive struct/class/union</li> |
| <li>“Template” is equivalent to “Generic”</li> |
| <li>Types can be looked up by their name via <code>SBTarget.FindFirstType(type_name)</code>. <code>SBTarget</code> can be |
| acquired via <code>SBValue.GetTarget</code></li> |
| <li><code>SBType.template_args</code> returns <code>None</code> instead of an empty list if the type has no generics</li> |
| <li>It is sometimes necessary to transform a type into the type you want via functions like |
| <code>SBType.GetArrayType</code> and <code>SBType.GetPointerType</code>. These functions cannot fail. They ask the |
| underlying LLDB <code>TypeSystem</code> plugin for the type, bypassing the debug info completely. Even if the |
| type does not exist in the debug info at all, these functions can create the appropriate type.</li> |
| <li><code>SBType.GetCanonicalType</code> is effectively <code>SBType.GetTypedefedType</code> + <code>SBType.GetUnqualifiedType</code>. |
| Unlike <code>SBType.GetTypedefedType</code>, it will always return a valid <code>SBType</code> regardless of whether or |
| not the original <code>SBType</code> is a typedef.</li> |
| <li><code>SBType.GetStaticFieldWithName</code> was added in LLDB 18. Unfortunately, backwards compatibility isn’t |
| always possible since the static fields are otherwise completely inaccessible.</li> |
| </ul> |
| <h1 id="example-provider-vect"><a class="header" href="#example-provider-vect">Example Provider: <code>Vec<T></code></a></h1> |
| <h2 id="syntheticprovider"><a class="header" href="#syntheticprovider">SyntheticProvider</a></h2> |
| <p>We start with the typical prelude, using <code>__slots__</code> since we have known fields. In addition to the |
| object itself, we also need to store the type of the elements because <code>Vec</code>’s heap pointer is a |
| <code>*mut u8</code>, not a <code>*mut T</code>. Rust is a statically typed language, so the type of <code>T</code> will never |
| change. That means we can store it during initialization. The heap pointer, length, and capacity |
| <em>can</em> change though, and thus are default initialized here.</p> |
| <pre><code class="language-python">import lldb |
| |
| class VecSyntheticProvider: |
| valobj: SBValue |
| data_ptr: SBValue |
| len: int |
| cap: int |
| element_type: SBType |
| |
| __slots__ = ( |
| "valobj", |
| "data_ptr", |
| "len", |
| "cap", |
| "element_type", |
| "__weakref__", |
| ) |
| |
| def __init__(valobj: SBValue, _dict) -> None: |
| self.valobj = valobj |
| # invalid type is a better default than `None` |
| self.element_type = SBType() |
| |
| # special handling to account for DWARF/PDB differences |
| if (arg := valobj.GetType().GetTemplateArgumentType(0)): |
| self.element_type = arg |
| else: |
| arg_name = next(get_template_args(valobj.GetTypeName())) |
| self.element_type = resolve_msvc_template_arg(arg_name, valobj.GetTarget()) |
| </code></pre> |
| <p>For the implementation of <code>get_template_args</code> and <code>resolve_msvc_template_arg</code>, please see: |
| <a href="https://github.com/rust-lang/rust/blob/main/src/etc/lldb_providers.py#L136"><code>lldb_providers.py</code></a>.</p> |
| <p>Next, the update function. We check if the pointer or length have changed. We can ommit checking the |
| capacity, as the number of children will remain the same unless <code>len</code> changes. If changing the |
| capacity resulted in a reallocation, <code>data_ptr</code>’s address would be different.</p> |
| <p>If <code>data_ptr</code> and <code>length</code> haven’t changed, we can take advantage of LLDB’s caching and return |
| early. If they have changed, we store the new values and tell LLDB to flush the cache.</p> |
| <pre><code class="language-python">def update(self): |
| ptr = self.valobj.GetChildMemberWithName("data_ptr") |
| len = self.valobj.GetChildMemberWithName("length").GetValueAsUnsigned() |
| |
| if ( |
| self.data_ptr.GetValueAsAddress() == ptr.GetValueAsAddress() |
| and self.len == len |
| ): |
| # Our child address offsets and child count are still valid |
| # so we can reuse cached children |
| return True |
| |
| self.data_ptr = ptr |
| self.len = len |
| |
| return False |
| </code></pre> |
| <p><code>has_children</code> and <code>num_children</code> are both straightforward:</p> |
| <pre><code class="language-python">def has_children(self) -> bool: |
| return True |
| |
| def num_children(self) -> int: |
| return self.len |
| </code></pre> |
| <p>When accessing elements, we expect values of the format <code>[0]</code>, <code>[1]</code>, etc. to mimic indexing. |
| Additionally, we still want the user to be able to quickly access the length and capacity, as they |
| can be very useful when debugging. We assign these values <code>u32::MAX - 1</code> and <code>u32::MAX - 2</code> |
| respectively, as we can almost surely guarantee that they will not overlap with element values. Note |
| that we can account for both the full and shorthand <code>capacity</code> name.</p> |
| <pre><code class="language-python"> def get_child_index(self, name: str) -> int: |
| index = name.lstrip("[").rstrip("]") |
| if index.isdigit(): |
| return int(index) |
| if name == "len": |
| return lldb.UINT32_MAX - 1 |
| if name == "cap" or name == "capacity": |
| return lldb.UINT32_MAX - 2 |
| |
| return -1 |
| </code></pre> |
| <p>We now have to properly coordinate <code>get_child_at_index</code> so that the elements, length, and capacity |
| are all accessible.</p> |
| <pre><code class="language-python">def get_child_at_index(self, index: int) -> SBValue: |
| if index == UINT32_MAX - 1: |
| return self.valobj.GetChildMemberWithName("len") |
| if index == UINT32_MAX - 2: |
| return ( |
| self.valobj.GetChildMemberWithName("buf") |
| .GetChildMemberWithName("inner") |
| .GetChildMemberWithName("cap") |
| .GetChildAtIndex(0) |
| .Clone("capacity") |
| ) |
| addr = self.data_ptr.GetValueAsAddress() |
| addr += index * self.element_type.GetByteSize() |
| return self.valobj.CreateValueFromAddress(f"[{index}]", addr, self.element_type) |
| </code></pre> |
| <p>For the type’s display name, we can strip the path qualifier. User defined types named |
| <code>Vec</code> will end up fully qualified, so there shouldn’t be any ambiguity. We can also remove the |
| allocator generic, as it’s very very rarely useful. We use <code>get_template_args</code> instead of |
| <code>self.element_type.GetName()</code> for 3 reasons:</p> |
| <ol> |
| <li>If we fail to resolve the element type for any reason, <code>self.valobj</code>’s type name can still let |
| the user know what the real type of the element is</li> |
| <li>Type names are not subject to the limitations of DWARF and PDB nodes, so the template type in |
| the name will reflect things like <code>*const</code>/<code>*mut</code> and <code>&</code>/<code>&mut</code>.</li> |
| <li>We do not currently (Nov 2025) normalize MSVC type names, but once we do, we will need to work with the |
| string-names of types anyway. It’s also much easier to cache a string-to-string conversion compared |
| to an <code>SBType</code>-to-string conversion.</li> |
| </ol> |
| <pre><code class="language-python">def get_type_name(self) -> str: |
| return f"Vec<{next(get_template_args(self.valobj))}>" |
| </code></pre> |
| <p>There isn’t an appropriate primitive value with which to represent a <code>Vec</code>, so we simply ommit |
| the <code>get_value</code> function.</p> |
| <h2 id="summaryprovider"><a class="header" href="#summaryprovider">SummaryProvider</a></h2> |
| <p>The summary provider is very simple thanks to our synthetic provider. The only real hiccup is that |
| <code>GetSummary</code> only returns a value if the object’s type has a <code>SummaryProvider</code>. If it doesn’t, it |
| will return an empty string which is not ideal. In a full set of visualizer scripts, we can ensure |
| that every type that doesn’t have a <code>GetSummary()</code> or a <code>GetValue()</code> is a struct, and then delegate |
| to a generic <code>StructSummaryProvider</code>. For this demonstration, I will gloss over that detail.</p> |
| <pre><code class="language-python">def VecSummaryProvider(valobj: SBValue, _lldb_internal) -> str: |
| children = [] |
| for i in range(valobj.GetNumChildren()): |
| child = valobj.GetChildAtIndex(i) |
| summary = child.GetSummary() |
| if summary is None: |
| summary = child.GetValue() |
| if summary is None: |
| summary = "{...}" |
| |
| children.append(summary) |
| |
| return f"vec![{", ".join(children)}]" |
| </code></pre> |
| <h2 id="enabling-the-providers"><a class="header" href="#enabling-the-providers">Enabling the providers</a></h2> |
| <p>Assume this synthetic is imported into <code>lldb_lookup.py</code></p> |
| <p>With CLI commands:</p> |
| <pre><code class="language-txt">type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust |
| type summary add -F lldb_lookup.summary_lookup -x "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust |
| </code></pre> |
| <p>With <code>__lldb_init_module</code>:</p> |
| <pre><code class="language-python">def __lldb_init_module(debugger: SBDebugger, _dict: LLDBOpaque): |
| # Ensure the category exists and is enabled |
| rust_cat = debugger.GetCategory("Rust") |
| |
| if not rust_cat.IsValid(): |
| rust_cat = debugger.CreateCategory("Rust") |
| |
| rust_cat.SetEnabled(True) |
| |
| # Register Vec providers |
| vec_regex = r"^(alloc::([a-z_]+::)+)Vec<.+>$" |
| sb_name = lldb.SBTypeNameSpecifier(vec_regex, is_regex=True) |
| |
| sb_synth = lldb.SBTypeSynthetic.CreateWithClassName("lldb_lookup.VecSyntheticProvider") |
| sb_synth.SetOptions(lldb.eTypeOptionCascade) |
| |
| sb_summary = lldb.SBTypeSummary.CreateWithFunctionName("lldb_lookup.VecSummaryProvider") |
| sb_summary.SetOptions(lldb.eTypeOptionCascade) |
| |
| rust_cat.AddTypeSynthetic(sb_name, sb_synth) |
| rust_cat.AddSummary(sb_name, sb_summary) |
| </code></pre> |
| <h2 id="output"><a class="header" href="#output">Output</a></h2> |
| <p>Without providers:</p> |
| <pre><code class="language-text">(lldb) v vec_v |
| (alloc::vec::Vec<int, alloc::alloc::Global>) vec_v = { |
| buf = { |
| inner = { |
| ptr = { |
| pointer = (pointer = "\n") |
| _marker = {} |
| } |
| cap = (__0 = 5) |
| alloc = {} |
| } |
| _marker = {} |
| } |
| len = 5 |
| } |
| (lldb) v vec_v[0] |
| error: <user expression 0>:1:6: subscripted value is not an array or pointer |
| 1 | vec_v[0] |
| | ^ |
| </code></pre> |
| <p>With providers (<code>v <var_name></code> prints the summary and then a list of all children):</p> |
| <pre><code class="language-text">(lldb) v vec_v |
| (Vec<int>) vec_v = vec![10, 20, 30, 40, 50] { |
| [0] = 10 |
| [1] = 20 |
| [2] = 30 |
| [3] = 40 |
| [4] = 50 |
| } |
| (lldb) v vec_v[0] |
| (int) vec_v[0] = 10 |
| </code></pre> |
| <p>We can also confirm that the “hidden” length and capacity are still accessible:</p> |
| <pre><code class="language-text">(lldb) v vec_v.len |
| (unsigned long long) vec_v.len = 5 |
| (lldb) v vec_v.capacity |
| (unsigned long long) vec_v.capacity = 5 |
| (lldb) v vec_v.cap |
| (unsigned long long) vec_v.cap = 5 |
| </code></pre> |
| |
| </main> |
| |
| <nav class="nav-wrapper" aria-label="Page navigation"> |
| <!-- Mobile navigation buttons --> |
| <a rel="prev" href="../debuginfo/debugger-visualizers.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left"> |
| <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span> |
| </a> |
| |
| <a rel="next prefetch" href="../debuginfo/gdb-visualizers.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right"> |
| <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span> |
| </a> |
| |
| <div style="clear: both"></div> |
| </nav> |
| </div> |
| </div> |
| |
| <nav class="nav-wide-wrapper" aria-label="Page navigation"> |
| <a rel="prev" href="../debuginfo/debugger-visualizers.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left"> |
| <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span> |
| </a> |
| |
| <a rel="next prefetch" href="../debuginfo/gdb-visualizers.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right"> |
| <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span> |
| </a> |
| </nav> |
| |
| </div> |
| |
| <template id=fa-eye><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg></span></template> |
| <template id=fa-eye-slash><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c5.2-11.8 8-24.8 8-38.5c0-53-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zm223.1 298L373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5z"/></svg></span></template> |
| <template id=fa-copy><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M502.6 70.63l-61.25-61.25C435.4 3.371 427.2 0 418.7 0H255.1c-35.35 0-64 28.66-64 64l.0195 256C192 355.4 220.7 384 256 384h192c35.2 0 64-28.8 64-64V93.25C512 84.77 508.6 76.63 502.6 70.63zM464 320c0 8.836-7.164 16-16 16H255.1c-8.838 0-16-7.164-16-16L239.1 64.13c0-8.836 7.164-16 16-16h128L384 96c0 17.67 14.33 32 32 32h47.1V320zM272 448c0 8.836-7.164 16-16 16H63.1c-8.838 0-16-7.164-16-16L47.98 192.1c0-8.836 7.164-16 16-16H160V128H63.99c-35.35 0-64 28.65-64 64l.0098 256C.002 483.3 28.66 512 64 512h192c35.2 0 64-28.8 64-64v-32h-47.1L272 448z"/></svg></span></template> |
| <template id=fa-play><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg></span></template> |
| <template id=fa-clock-rotate-left><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M75 75L41 41C25.9 25.9 0 36.6 0 57.9V168c0 13.3 10.7 24 24 24H134.1c21.4 0 32.1-25.9 17-41l-30.8-30.8C155 85.5 203 64 256 64c106 0 192 86 192 192s-86 192-192 192c-40.8 0-78.6-12.7-109.7-34.4c-14.5-10.1-34.4-6.6-44.6 7.9s-6.6 34.4 7.9 44.6C151.2 495 201.7 512 256 512c141.4 0 256-114.6 256-256S397.4 0 256 0C185.3 0 121.3 28.7 75 75zm181 53c-13.3 0-24 10.7-24 24V256c0 6.4 2.5 12.5 7 17l72 72c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-65-65V152c0-13.3-10.7-24-24-24z"/></svg></span></template> |
| |
| |
| |
| <script> |
| window.playground_copyable = true; |
| </script> |
| |
| |
| <script src="../elasticlunr-ef4e11c1.min.js"></script> |
| <script src="../mark-09e88c2c.min.js"></script> |
| <script src="../searcher-c2a407aa.js"></script> |
| |
| <script src="../clipboard-1626706a.min.js"></script> |
| <script src="../highlight-abc7f01d.js"></script> |
| <script src="../book-a0b12cfe.js"></script> |
| |
| <!-- Custom JS scripts --> |
| <script src="../mermaid-cc85ecea.min.js"></script> |
| <script src="../mermaid-init-4533fb11.js"></script> |
| |
| |
| |
| </div> |
| </body> |
| </html> |