LLDB Reproducers Jonas Devlieghere, Apple LLVM Developers - - PowerPoint PPT Presentation

lldb reproducers
SMART_READER_LITE
LIVE PREVIEW

LLDB Reproducers Jonas Devlieghere, Apple LLVM Developers - - PowerPoint PPT Presentation

LLDB Reproducers Jonas Devlieghere, Apple LLVM Developers Meeting, Brussels, Belgium, April 2019 "The debugger doesn't work" Somebody on the internet LLDB Bugs $ lldb ./a.out (lldb) target create


slide-1
SLIDE 1

Jonas Devlieghere, Apple LLVM Developers’ Meeting, Brussels, Belgium, April 2019

  • LLDB Reproducers
slide-2
SLIDE 2

"The debugger doesn't work"

  • — Somebody on the internet
slide-3
SLIDE 3

LLDB Bugs

$ lldb ./a.out (lldb) target create "a.out" (lldb) b main.cpp:12 ... (lldb) run ... (lldb) expr @import Foo (lldb) expr Bar cannot materialize variable

slide-4
SLIDE 4

LLDB Bug Reports

Bob Alice

"Hey this doesn't work..."

 

slide-5
SLIDE 5

LLDB Bug Reports

"Can you attach the expr log?"

 

Bob Alice

slide-6
SLIDE 6

LLDB Bug Reports

Expression log

 

Bob Alice

slide-7
SLIDE 7

LLDB Bug Reports

"Can you attach the type log?"

 

Bob Alice

slide-8
SLIDE 8

LLDB Bug Reports

Type log

 

Bob Alice

slide-9
SLIDE 9

LLDB Bug Reports

 

"How do I reproduce?"

Bob Alice

slide-10
SLIDE 10

LLDB Bug Reports

Steps to reproduce

 

Bob Alice

slide-11
SLIDE 11

LLDB Bug Reports

🤭 

"It doesn't reproduce..."

Bob Alice

slide-12
SLIDE 12

Reproducers

  • Automate the process
  • Everything needed to reproduce
  • Inspired by clang
slide-13
SLIDE 13

Reproducers

"Hey this doesn't work..."

 

📧

Bob Alice

slide-14
SLIDE 14

Reproducers

$ lldb ./a.out --capture (lldb) target create "a.out" (lldb) b main.cpp:12 ... (lldb) run ... (lldb) expr @import Foo (lldb) expr Bar cannot materialize variable (lldb) reproducer generate $ lldb --replay reproducer (lldb) target create "a.out" (lldb) b main.cpp:12 ... (lldb) run ... (lldb) expr @import Foo (lldb) expr Bar cannot materialize variable

 

📧

slide-15
SLIDE 15

LLDB Reproducers

slide-16
SLIDE 16

Reconstruct the debugger's state

  • How we get there is more important than the final result
  • Capture data
  • Debug during replay
slide-17
SLIDE 17

Information

User interaction

  • Commands typed in the command line interpreter
  • Use of the public API

System interaction

  • Data from the (file) system
  • Data from the process being debugged
slide-18
SLIDE 18

Minimize impact

  • Don't hide or introduce bugs
  • Reuse existing infrastructure
  • Transparency and abstraction
slide-19
SLIDE 19

Components

slide-20
SLIDE 20

User Interaction

  • Command Line Interpreter
  • Public API (Scripting Bridge)
  • Files
  • GDB Remote Protocol
slide-21
SLIDE 21

Command Interpreter

$ lldb ./a.out (lldb) target create "a.out" (lldb) b main.cpp:12 ... (lldb) run ... (lldb) expr @import Foo (lldb) expr Bar

slide-22
SLIDE 22

User Interaction

  • Command Line Interpreter
  • Public API (Scripting Bridge)
  • Files
  • GDB Remote Protocol
slide-23
SLIDE 23

Stable C++ API

  • Accessible through Python wrappers
  • Used by IDEs such as Xcode, Eclipse, Visual Studio Code
  • How the command line driver is implemented
slide-24
SLIDE 24

Python Example

import lldb debugger = lldb.SBDebugger.Create() target = debugger.CreateTarget("/path/to/a.out") target.BreakpointCreateByName("foo") process = target.LaunchSimple(...)

slide-25
SLIDE 25

Capture and replay API calls

  • Capture the call and its argument values
  • Capture the return value
slide-26
SLIDE 26

API Boundary

API boundary

Python SBDebugger SBTarget

CreateTarget() GetByteOrder()

slide-27
SLIDE 27

API Boundary

API boundary

Python SBDebugger SBTarget

GetByteOrder() CreateTarget() GetByteOrder()

slide-28
SLIDE 28

Detecting API Boundaries

  • RAII object consisting of two booleans
  • Static boolean toggles when crossing the API boundary
  • Non-static boolean tracks if boundary needs to be reset
slide-29
SLIDE 29

Capturing Calls

  • Toggles the API boundary
  • Captures the call and its arguments
  • More than 2000 instances

lldb::SBThread SBValue::GetThread() { LLDB_RECORD_METHOD_NO_ARGS(lldb::SBThread, SBValue, GetThread); ... return LLDB_RECORD_RESULT(sb_thread); }

slide-30
SLIDE 30

Capturing Calls

  • Maps functions to unique identifier
  • Type safe
  • Synthesizes deserialization logic

LLDB_REGISTER_METHOD(void, SBDebugger, SetAsync, (bool)); LLDB_REGISTER_METHOD(bool, SBDebugger, GetAsync, ()); LLDB_REGISTER_METHOD(void, SBDebugger, SkipAppInitFiles, (bool)); LLDB_REGISTER_METHOD(void, SBDebugger, SkipAppInitFiles,(bool));

slide-31
SLIDE 31

lldb-instr

  • Utility on top of libTooling
  • Traverses the clang AST
  • Inserts the record and register macros
slide-32
SLIDE 32

Capturing Arguments

  • Stream values to file
  • Look at underlying value for pointers and references
slide-33
SLIDE 33

Capturing Objects

  • Index based on object address
  • Table keeps mapping between object and index

SBDebugger debugger = SBDebugger::Create(); SBTarget target = debugger.createTarget(); SBLaunchInfo info("--arguments"); target.Launch(info);

Object Index debugger 1 target 2 info 3

slide-34
SLIDE 34

Replay

Public API

while (deserializer.HasData(1)) { unsigned id = deserializer.Deserialize<unsigned>(); GetReplayer(id)->operator()(deserializer); }

slide-35
SLIDE 35

Components

  • Command Line Interpreter
  • Public API (Scripting Bridge)
  • Files
  • GDB Remote Protocol

System Interaction

slide-36
SLIDE 36

Files

$ lldb ./a.out (lldb) target create "a.out" (binary) (lldb) b main.cpp:12 (debug information) ... (lldb) run (shared libraries) ... (lldb) expr @import Foo (headers) (lldb) expr Bar

slide-37
SLIDE 37

Virtual File System

  • Use files from the reproducer
  • YAML mapping between virtual and real paths
  • Lifted from clang to LLVM
  • Devirtualize to support FILE* and file descriptors
slide-38
SLIDE 38

Filesystem Class

  • Wrapper around the VFS
  • All file system access must go through this class
  • FileCollector used for recording files used by LLDB & clang
slide-39
SLIDE 39

Components

  • Command Line Interpreter
  • Public API (Scripting Bridge)
  • Files
  • GDB Remote Protocol

System Interaction

slide-40
SLIDE 40

GDB Remote Protocol

LLDB debugserver a.out

GDB Remote Protocol Implementation Defined

  • Simple command and response protocol
  • Read and write memory, registers and to start/stop the process
  • Designed for remote debugging but also used locally
slide-41
SLIDE 41

Capture

LLDB debugserver a.out

GDB Remote Protocol Implementation Defined

Reply #1 Reply #2 Reply #3 Reply #4 Reply #5 ...

slide-42
SLIDE 42

Replay

LLDB replay server

GDB Remote Protocol

  • Responds with recorded reply (in order)
  • Fully transparent to the debugger
  • Replay remote debug sessions

Reply #1 Reply #2 Reply #3 Reply #4 Reply #5 ...

slide-43
SLIDE 43

Limitations and future work

slide-44
SLIDE 44

API Arguments

  • Function pointers
  • Void & data pointers

ID 10 Data 0xFF ... 0x00 Length 56

void Foo(char* data, size_t length);

slide-45
SLIDE 45

Memory Management

  • No lifetime tracking for now
  • Pointer addresses can be reused
  • Objects created during replay are never deallocated
slide-46
SLIDE 46

Swift

  • Virtual File System
  • FileCollector callback
slide-47
SLIDE 47

Reproducer Size

  • Large files
  • Many files
  • Do we need all of them?
slide-48
SLIDE 48

Crashes

  • No guarantees in the signal handler
  • Do something smart like clang
slide-49
SLIDE 49

Privacy

  • Reproducers contain a lot of potentially sensitive information
  • Need to be clear and upfront about this to the user
slide-50
SLIDE 50
  • Please try it out!
  • bugs.llvm.org
slide-51
SLIDE 51

LLDB Reproducers
 Jonas Devlieghere, LLVM Developers’ Meeting, Brussels, Belgium, April 2019

  • Questions?