Skip to content

Instantly share code, notes, and snippets.

@brennanMKE
Last active May 27, 2025 18:25
Show Gist options
  • Save brennanMKE/fbb289acb722704c0e95cb2d946c2506 to your computer and use it in GitHub Desktop.
Save brennanMKE/fbb289acb722704c0e95cb2d946c2506 to your computer and use it in GitHub Desktop.
Debugging with LLDB

βœ… Debugging Memory Leaks with LLDB

πŸ” 1. Inspect What Is at a Given Memory Address

Yes β€” if you have a memory address from a leak report, LLDB can tell you what object it points to:

memory read --format x --size 8 --count 1 0xADDRESS

Or better:

expr -O -- (id)0xADDRESS

If it's a Swift object:

expr -l Swift -- unsafeBitCast(0xADDRESS, to: MyType.self)

This can show properties and type name if symbols are available.


πŸ”— 2. Check If an Instance Is Still Retained

No β€” LLDB cannot directly tell you what is retaining an object. Swift and Objective-C don’t expose full retain graph inspection APIs via LLDB.

But you can:

  • Set a watchpoint on the retain count (on Obj-C isa or Swift reference count internals).
  • Use po or expr to print suspected references (e.g., arrays, dictionaries, closures).

βœ… Use leaks and heap

πŸ“ˆ leaks (macOS command-line tool)

leaks PID
  • Shows leaked memory regions and backtraces
  • Often identifies leaked Swift/Obj-C objects by class/type
  • Best run from Terminal outside LLDB while app is paused

You can also run leaks from within LLDB:

process detach
! leaks PID
process attach --pid PID

πŸ“Š heap (part of malloc_history)

heap PID
  • Shows live allocations grouped by type
  • Helpful to estimate how many instances of a type exist
  • Can show where a large group of leaked instances were allocated

πŸ“¦ Use malloc_history to Trace an Address

malloc_history PID 0xADDRESS
  • Shows allocation stack trace of the specific memory address
  • Essential to know where it was allocated

πŸ” Debugging Workflow

  1. Pause the app (breakpoint or attach)

  2. Run leaks PID or heap PID in Terminal

  3. Copy a suspicious memory address

  4. In LLDB:

    expr -O -- (id)0xADDRESS
    

    or

    expr -l Swift -- unsafeBitCast(0xADDRESS, to: SuspectedType.self)
    
  5. Use malloc_history to trace allocation site:

    malloc_history PID 0xADDRESS
  6. Inspect references in LLDB by printing containers or static properties


πŸ”Ž Limitations

  • LLDB can inspect memory and state but not ownership or retain graphs
  • Swift ARC doesn’t expose retain counts or owners
  • Instruments or Xcode's Memory Graph is better for visualizing retain cycles

🧭 Debugging with LLDB

βœ… Set a breakpoint on a Swift method

breakpoint set --name 'methodName'

βœ… Set breakpoint on a method in a specific type

Use this syntax when you know both the type and the method name:

breakpoint set --name 'TypeName.methodName'

This works in many Swift contexts, especially when the symbol names are unambiguous.


πŸ“œ Using command source to Run LLDB Scripts

You can write a .lldb file containing LLDB commands to automate breakpoint management.

🧾 Example: breakpoints.lldb

# Set breakpoints on specific functions
breakpoint set --func-regex MyClass\.startWork
breakpoint set --func-regex Logger\.logEvent

# Disable some of them (use IDs if known)
breakpoint disable 1
breakpoint disable 2

▢️ Run the script from LLDB:

command source breakpoints.lldb

Or when launching LLDB:

lldb -s breakpoints.lldb MyApp

πŸ“¦ Debugging Methods in Dependencies (Swift Modules or Frameworks)

When debugging dependencies where symbols might be mangled or ambiguous, use these precise commands.

πŸ” Lookup all functions in a type

image lookup -rn TypeName

Use this to inspect all Swift-mangled functions matching TypeName in loaded modules.


🎯 Set a breakpoint using regex

This is very useful for targeting symbols with Swift name mangling:

breakpoint set --func-regex TypeName\.methodName

You can even do partial matches:

breakpoint set --func-regex myType\.myFunc

🧬 Break on functions in a Swift module

If you know the module name (e.g. MyLib) and want to break on an exact method:

breakpoint set --func-regex MyLib\.MyType\.myMethod

If that doesn't work (due to name mangling), try just the method:

breakpoint set --func-regex myMethod

Use image lookup to verify symbol presence if needed:

image lookup -r -n myMethod

🧠 LLDB Tips for Swift

See backtraces to verify correct frames:

thread backtrace

Print variable:

po myVar

Print the current Swift call stack with demangled names:

bt all

πŸ”§ Example: Set breakpoint on method in type from dependency

Assume Logger.log(message:) is defined in an external Swift package:

breakpoint set --func-regex Logger\.log

If this doesn’t work, use:

image lookup -r -n log

Then copy the exact mangled name or symbol signature and break on it:

breakpoint set --name "$s6Logger3log7messageySS_tF"

πŸ“š References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment