美文网首页
Swift进阶-LLDB调试

Swift进阶-LLDB调试

作者: sweetpf | 来源:发表于2019-01-31 10:42 被阅读9次

    工欲善其事,必先利其器。程序猿最好的利器就是开发工具,iOS开发者最基本,最关键的一点就是熟练使用Xcode,而LLDB则是Xcode中至关重要的一环。
    作为开发者,我们大部分的工作时间都用于调试,调试协议,调试UI,调试bug,用好LLDB,打遍iOS无敌手。

    LLDB拥有大量有用的调试命令:

    (lldb) help
    Debugger commands:
      apropos           -- List debugger commands related to a word or subject.
      breakpoint        -- Commands for operating on breakpoints (see 'help b' for
                           shorthand.)
      bugreport         -- Commands for creating domain-specific bug reports.
      command           -- Commands for managing custom LLDB commands.
      disassemble       -- Disassemble specified instructions in the current
                           target.  Defaults to the current function for the
                           current thread and stack frame.
      expression        -- Evaluate an expression on the current thread.  Displays
                           any returned value with LLDB's default formatting.
      frame             -- Commands for selecting and examing the current thread's
                           stack frames.
      gdb-remote        -- Connect to a process via remote GDB server.  If no host
                           is specifed, localhost is assumed.
      gui               -- Switch into the curses based GUI mode.
      help              -- Show a list of all debugger commands, or give details
                           about a specific command.
      kdp-remote        -- Connect to a process via remote KDP server.  If no UDP
                           port is specified, port 41139 is assumed.
      language          -- Commands specific to a source language.
      log               -- Commands controlling LLDB internal logging.
      memory            -- Commands for operating on memory in the current target
                           process.
      platform          -- Commands to manage and create platforms.
      plugin            -- Commands for managing LLDB plugins.
      process           -- Commands for interacting with processes on the current
                           platform.
      quit              -- Quit the LLDB debugger.
      register          -- Commands to access registers for the current thread and
                           stack frame.
      script            -- Invoke the script interpreter with provided code and
                           display any results.  Start the interactive interpreter
                           if no code is supplied.
      settings          -- Commands for managing LLDB settings.
      source            -- Commands for examining source code described by debug
                           information for the current target process.
      statistics        -- Print statistics about a debugging session
      target            -- Commands for operating on debugger targets.
      thread            -- Commands for operating on one or more threads in the
                           current process.
      type              -- Commands for operating on the type system.
      version           -- Show the LLDB debugger version.
      watchpoint        -- Commands for operating on watchpoints.
    Current command abbreviations (type 'help command alias' for more info):
      add-dsym  -- Add a debug symbol file to one of the target's current modules
                   by specifying a path to a debug symbols file, or using the
                   options to specify a module to download symbols for.
      attach    -- Attach to process by ID or name.
      b         -- Set a breakpoint using one of several shorthand formats.
      bt        -- Show the current thread's call stack.  Any numeric argument
                   displays at most that many frames.  The argument 'all' displays
                   all threads.
      c         -- Continue execution of all threads in the current process.
      call      -- Evaluate an expression on the current thread.  Displays any
                   returned value with LLDB's default formatting.
      continue  -- Continue execution of all threads in the current process.
      detach    -- Detach from the current target process.
      di        -- Disassemble specified instructions in the current target. 
                   Defaults to the current function for the current thread and
                   stack frame.
      dis       -- Disassemble specified instructions in the current target. 
                   Defaults to the current function for the current thread and
                   stack frame.
      display   -- Evaluate an expression at every stop (see 'help target
                   stop-hook'.)
      down      -- Select a newer stack frame.  Defaults to moving one frame, a
                   numeric argument can specify an arbitrary number.
      env       -- Shorthand for viewing and setting environment variables.
      exit      -- Quit the LLDB debugger.
      f         -- Select the current stack frame by index from within the current
                   thread (see 'thread backtrace'.)
      file      -- Create a target using the argument as the main executable.
      finish    -- Finish executing the current stack frame and stop after
                   returning.  Defaults to current thread unless specified.
      image     -- Commands for accessing information for one or more target
                   modules.
      j         -- Set the program counter to a new address.
      jump      -- Set the program counter to a new address.
      kill      -- Terminate the current target process.
      l         -- List relevant source code using one of several shorthand formats.
      list      -- List relevant source code using one of several shorthand formats.
      n         -- Source level single step, stepping over calls.  Defaults to
                   current thread unless specified.
      next      -- Source level single step, stepping over calls.  Defaults to
                   current thread unless specified.
      nexti     -- Instruction level single step, stepping over calls.  Defaults to
                   current thread unless specified.
      ni        -- Instruction level single step, stepping over calls.  Defaults to
                   current thread unless specified.
      p         -- Evaluate an expression on the current thread.  Displays any
                   returned value with LLDB's default formatting.
      parray    -- Evaluate an expression on the current thread.  Displays any
                   returned value with LLDB's default formatting.
      po        -- Evaluate an expression on the current thread.  Displays any
                   returned value with formatting controlled by the type's author.
      poarray   -- Evaluate an expression on the current thread.  Displays any
                   returned value with LLDB's default formatting.
      print     -- Evaluate an expression on the current thread.  Displays any
                   returned value with LLDB's default formatting.
      q         -- Quit the LLDB debugger.
      r         -- Launch the executable in the debugger.
      rbreak    -- Sets a breakpoint or set of breakpoints in the executable.
      repl      -- Evaluate an expression on the current thread.  Displays any
                   returned value with LLDB's default formatting.
      run       -- Launch the executable in the debugger.
      s         -- Source level single step, stepping into calls.  Defaults to
                   current thread unless specified.
      si        -- Instruction level single step, stepping into calls.  Defaults to
                   current thread unless specified.
      sif       -- Step through the current block, stopping if you step directly
                   into a function whose name matches the TargetFunctionName.
      step      -- Source level single step, stepping into calls.  Defaults to
                   current thread unless specified.
      stepi     -- Instruction level single step, stepping into calls.  Defaults to
                   current thread unless specified.
      t         -- Change the currently selected thread.
      tbreak    -- Set a one-shot breakpoint using one of several shorthand
                   formats.
      undisplay -- Stop displaying expression at every stop (specified by stop-hook
                   index.)
      up        -- Select an older stack frame.  Defaults to moving one frame, a
                   numeric argument can specify an arbitrary number.
      x         -- Read from the memory of the current target process.
    

    先简单翻一下,做个大概了解

    Debugger commands:
    apropos  列出与Word或主题相关的调试器命令
    breakpoint  操作断点的命令
    bugreport 创建特定领域错误报告的命令
    command  管理自定义LLDB命令的命令
    disassemble 拆卸当前指定的指令,默认为当前函数为当前线程和堆栈帧
    expression 评估当前线程上的表达式。任何返回值与LLDB的默认格式。
    frame  命令选择和检查当前线程的堆栈帧,GDB远程通过远程GDB服务器连接到进程,如果没有主机指定localhost假设
    gui 切换到基于诅咒的GUI模式。
    kdp-remote 通过远程KDP服务器连接进程,如果没有UDP端口被指定,假定端口41139。
    language 特定于源语言的命令log 控制LLDB内部记录命令。
    memory 在当前目标上操作内存的命令过程
    platform  管理和创建平台的命令
    plugin  管理LLDB插件
    process  与当前进程交互的命令平台
    quit  退出LLDB调试器。
    register  为当前线程访问寄存器的命令栈帧
    script  使用提供的代码调用脚本解释器,显示任何结果。启动交互式解释器,如果没有提供代码。
    
    settings  管理LLDB设置命令
    source  检查由调试描述的源代码的命令,当前目标过程的信息。
    target  在调试器对象上操作的命令
    thread  中的一个或多个线程操作的命令目前的过程
    type  在类型系统上操作的命令
    version  显示LLDB调试器版本
    watchpoint  操作上观察点的命令.当前命令缩写(类型“帮助命令别名”以获取更多信息)
    add-dsym 将调试符号文件添加到目标当前模块中的一个通过指定调试符号文件的路径,或使用选项来指定下载符号的模块
    attach  通过ID或名称附加到进程
    b 使用几个速记格式中的一个设置断点
    bt 显示当前线程的调用堆栈。任何数字参数最多显示许多帧。参数“所有”显示所有的线程
    c  继续执行当前进程中的所有线程
    call  评估当前线程上的表达式。显示任何返回值与LLDB的默认格式
    continue  继续执行当前进程中的所有线程
    detach 从当前目标进程分离
    di  拆卸当前目标中指定的指令,默认为当前线程的当前功能和栈帧
    dis  拆卸当前目标中指定的指令,默认为当前线程的当前功能和栈帧
    display  在每一站评估表达式(参见“帮助目标”停止钩子)
    down 选择一个较新的堆栈帧。默认为移动一帧数字参数可以指定任意数量
    env 查看和设置环境变量的简写
    exit  退出LLDB调试器
    f 从当前范围内选择索引的当前堆栈帧线程(见螺纹回溯”。)
    file  使用参数作为主要可执行文件创建目标
    finish 完成执行当前堆栈帧后停止返回,默认为当前线程,除非指定
    image  为一个或多个目标访问信息的命令模块
    j  将程序计数器设置为新地址
    jump  将程序计数器设置为新地址
    kill  终止当前目标进程
    l  使用几个速记中的一个列出相关的源代码格式
    list 使用几个速记中的一个列出相关的源代码格式
    n  源级单步,单步调用。默认为当前线程,除非指定
    next 源级单步,单步调用。默认为当前线程,除非指定
    nexti  单步单步执行指令,默认为当前线程,除非指定
    ni  单步单步执行指令,默认为当前线程,除非指定
    p  评估当前线程上的表达式。显示任何返回值与LLDB的默认格式
    parray 评估当前线程上的表达式。显示任何返回值与LLDB的默认格式
    po  评估当前线程上的表达式。显示任何由类型作者控制的格式返回值
    poarray 评估当前线程上的表达式。显示任何返回值与LLDB的默认格式
    print  评估当前线程上的表达式。显示任何返回值与LLDB的默认格式
    q  退出LLDB调试器
    r  在调试器中启动可执行文件
    rbreak  在可执行文件中设置断点或断点集。
    repl  评估当前线程上的表达式。显示任何返回值与LLDB的默认格式
    run  在调试器中启动可执行文件
    s  源级单步,单步调用。默认为当前线程,除非指定
    si 单步单步执行指令,默认为当前线程,除非指定
    sif  通过当前块,如果直接单步执行停止为一个函数的名称相匹配的targetfunctionname
    step  源级单步,单步调用。默认为当前线程,除非指定
    stepi  单步单步执行指令,默认为当前线程,除非指定
    t  更改当前选定的线程
    tbreak  使用一一个快捷键中的一个设置断点格式
    undisplay  停止在每一站显示表达式(由停止钩子指定)指标。)
    up 选择一个旧的堆栈帧。默认为移动一帧,一个数字参数可以指定任意数量
    x  从当前目标进程的内存中读取
    

    其中一些常见的重要命令我会提炼出来跟大家一起探讨:

    • 获取变量值: expression , e , print , po , p
    • 获取执行环境+特定语言命令: bugreport , frame , language
    • 执行流程控制: process , breakpoint , thread , watchpoint
    • 单步调试:n,s,finish,c
    • 其他: command , platform , gui,image

    基本功能:获取变量值和状态

    调试最基本的功能是打印和修改变量的值,单步调试,确定是不是按照设定的方式运行,便于快速定位。
    命令: expression , e , print , po , p

    • expression、e指令: 既可以打印也可以赋值(后面有例子详解)
    • print指令: 除了 print 命令没有可用选项无需传递参数外, print 和 expression -- 几乎一样。
    • p指令: 可打印其对象类型、内存地址以及该对象的值等具体信息,print的简写
    • po指令: 是打印其调用description方法得到的值。实际上,po指令就是 e -O -- 的别名
    • expr指令: expression的简写
    • call指令: 调用方法的意思

    例如:

    func sum(_ a: Int, _ b: Int) -> Int {
            return a + b
        }
    
    sum(5, 4)
    

    p指令结果:

    (lldb) p a
    (Int) $R0 = 5
    

    po指令结果:

    (lldb) po a
    5
    

    e指令结果:

    (lldb) e a
    (Int) $R6 = 5
    

    e赋值结果:

    (lldb) e b = 10
    (lldb) po a+b
    15
    

    ------分割线------
    看完基本指令,再来深入了解下expression指令。
    expression命令拥有大约30个选项,可以调用help命令先大概了解下:

    help expression
         Evaluate an expression on the current thread.  Displays any returned value
         with LLDB's default formatting.  Expects 'raw' input (see 'help
         raw-input'.)
    
    Syntax: expression <cmd-options> -- <expr>
    
    Command Options Usage:
      expression [-AFLORTgp] [-f <format>] [-G <gdb-format>] [-a <boolean>] [-i <boolean>] [-t <unsigned-integer>] [-u <boolean>] [-l <source-language>] [-X <boolean>] [-v[<description-verbosity>]] [-j <boolean>] [-d <none>] [-S <boolean>] [-D <count>] [-P <count>] [-Y[<count>]] [-V <boolean>] [-Z <count>] -- <expr>
      expression [-AFLORTgp] [-a <boolean>] [-i <boolean>] [-t <unsigned-integer>] [-u <boolean>] [-l <source-language>] [-X <boolean>] [-j <boolean>] [-d <none>] [-S <boolean>] [-D <count>] [-P <count>] [-Y[<count>]] [-V <boolean>] [-Z <count>] -- <expr>
      expression [-r] -- <expr>
      expression <expr>
    
           -A ( --show-all-children )
                Ignore the upper bound on the number of children to show.
    
           -D <count> ( --depth <count> )
                Set the max recurse depth when dumping aggregate types (default is
                infinity).
    
           -F ( --flat )
                Display results in a flat format that uses expression paths for
                each variable or member.
    
           -G <gdb-format> ( --gdb-format <gdb-format> )
                Specify a format using a GDB format specifier string.
    
           -L ( --location )
                Show variable location information.
    
           -O ( --object-description )
                Display using a language-specific description API, if possible.
    
           -P <count> ( --ptr-depth <count> )
                The number of pointers to be traversed when dumping values (default
                is zero).
    
           -R ( --raw-output )
                Don't use formatting options.
    
           -S <boolean> ( --synthetic-type <boolean> )
                Show the object obeying its synthetic provider, if available.
    
           -T ( --show-types )
                Show variable types when dumping values.
    
           -V <boolean> ( --validate <boolean> )
                Show results of type validators.
    
           -X <boolean> ( --apply-fixits <boolean> )
                If true, simple fix-it hints will be automatically applied to the
                expression.
    
           -Y[<count>] ( --no-summary-depth=[<count>] )
                Set the depth at which omitting summary information stops (default
                is 1).
    
           -Z <count> ( --element-count <count> )
                Treat the result of the expression as if its type is an array of
                this many values.
    
           -a <boolean> ( --all-threads <boolean> )
                Should we run all threads if the execution doesn't complete on one
                thread.
    
           -d <none> ( --dynamic-type <none> )
                Show the object as its full dynamic type, not its static type, if
                available.
                Values: no-dynamic-values | run-target | no-run-target
    
           -f <format> ( --format <format> )
                Specify a format to be used for display.
    
           -g ( --debug )
                When specified, debug the JIT code by setting a breakpoint on the
                first instruction and forcing breakpoints to not be ignored (-i0)
                and no unwinding to happen on error (-u0).
    
           -i <boolean> ( --ignore-breakpoints <boolean> )
                Ignore breakpoint hits while running expressions
    
           -j <boolean> ( --allow-jit <boolean> )
                Controls whether the expression can fall back to being JITted if
                it's not supported by the interpreter (defaults to true).
    
           -l <source-language> ( --language <source-language> )
                Specifies the Language to use when parsing the expression.  If not
                set the target.language setting is used.
    
           -p ( --top-level )
                Interpret the expression as a complete translation unit, without
                injecting it into the local context.  Allows declaration of
                persistent, top-level entities without a $ prefix.
    
           -r ( --repl )
                Drop into Swift REPL
    
           -t <unsigned-integer> ( --timeout <unsigned-integer> )
                Timeout value (in microseconds) for running the expression.
    
           -u <boolean> ( --unwind-on-error <boolean> )
                Clean up program state if the expression causes a crash, or raises
                a signal.  Note, unlike gdb hitting a breakpoint is controlled by
                another option (-i).
    
           -v[<description-verbosity>] ( --description-verbosity=[<description-verbosity>] )
                How verbose should the output of this expression be, if the object
                description is asked for.
                Values: compact | full
    
    Single and multi-line expressions:
    
        The expression provided on the command line must be a complete expression
        with no newlines.  To evaluate a multi-line expression, hit a return after
        an empty expression, and lldb will enter the multi-line expression editor.
        Hit return on an empty line to end the multi-line expression.
    
    Timeouts:
    
        If the expression can be evaluated statically (without running code) then
        it will be.  Otherwise, by default the expression will run on the current
        thread with a short timeout: currently .25 seconds.  If it doesn't return
        in that time, the evaluation will be interrupted and resumed with all
        threads running.  You can use the -a option to disable retrying on all
        threads.  You can use the -t option to set a shorter timeout.
    
    User defined variables:
    
        You can define your own variables for convenience or to be used in
        subsequent expressions.  You define them the same way you would define
        variables in C.  If the first character of your user defined variable is a
        $, then the variable's value will be available in future expressions,
        otherwise it will just be available in the current expression.
    
    Continuing evaluation after a breakpoint:
    
        If the "-i false" option is used, and execution is interrupted by a
        breakpoint hit, once you are done with your investigation, you can either
        remove the expression execution frames from the stack with "thread return
        -x" or if you are still interested in the expression result you can issue
        the "continue" command and the expression evaluation will complete and the
        expression result will be available using the "thread.completed-expression"
        key in the thread format.
    
    Examples:
    
        expr my_struct->a = my_array[3]
        expr -f bin -- (index * 8) + 5
        expr unsigned int $foo = 5
        expr char c[] = \"foo\"; c[0]
         
         Important Note: Because this command takes 'raw' input, if you use any
         command options you must use ' -- ' between the end of the command options
         and the beginning of the raw input.
    

    LLDB使用双破折号--分隔选项和表达式:

    (lldb) expression <some flags> -- <variable></variable></some flags>
    

    下面列出了几个比较常用的选项:

    • D ( --depth ) - 设置打印聚合类型的递归深度(默认无限递归)。
    • O ( --object-desctiption ) - 打印description方法。
    • T ( --show-types ) - 显示每个变量的类型。
    • f ( --format ) - 设置输出格式。
    • i ( --ignore-breakpoints ) - 运行表达式时忽略表达式内的断点。

    获取执行环境+特定语言命令

    bugreport , frame , language

    • bugreport
      LLDB的 bugreport 命令可以生成一份详细的app当前状态的报告。该命令对于想要延迟追踪定位问题非常有用。为了保存app的状态,你可以使用 bugreport 来生成报告。
    help bugreport
         Commands for creating domain-specific bug reports.
    
    Syntax: bugreport <subcommand> [<subcommand-options>]
    
    The following subcommands are supported:
    
          unwind -- Create a bugreport for a bug in the stack unwinding code.
    
    For more help on any particular subcommand, type 'help <command> <subcommand>'.
    

    可以看到,bugreport的参数只有unwind,即:

    (lldb) bugreport unwind --outfile <path to output file></path to output file>
    
    • frame

    • language

    单步调试

    单步调试,修改指针变量的值,观测程序不同变化
    Xcode调试面板上实际已经有了按钮去实现,再这里简单介绍下:
    n 命令,代表 Step Over 操作。
    s 命令,代表 Step Into 操作。
    finish 命令,代表 Step Out 操作。
    c 命令,代表恢复程序执行操作。

    其他:

    • command
    • platform
    • gui
    • image
      1、image lookup --address寻址,定位异常代码位置
      举例说明,下面这段代码,执行的时候必然会出现异常,因为越界了:
    NSString *str = @"245656";
    [str substringFromIndex:10];
    

    2、image lookup --type查看类型

    ------------------------------分割线------------------------------
    ------------------------------分割线------------------------------
    ------------------------------分割线------------------------------
    --------------------------重要事情说三遍-------------------------

    编辑断点

    介绍完命令后,来个五星推荐必备技能:编辑断点!!编辑断点!!编辑断点!!
    断点调试是一把刀,帮助我们披荆斩棘,而编辑断点则是磨刀石,能够让我们的刀更锋利,所向披靡。

    相关文章

      网友评论

          本文标题:Swift进阶-LLDB调试

          本文链接:https://www.haomeiwen.com/subject/mgfksqtx.html