【问题标题】:Using lldb to display function outparam results使用 lldb 显示函数超参数结果
【发布时间】:2020-05-15 11:38:46
【问题描述】:

我目前正在使用 lldb 调试一个非常大的应用程序,并且我对某个函数的所有调用感兴趣(这里是 pthread_create)。我想知道调用堆栈和所有这些调用的结果,它们作为输出参数传递。

获取调用栈很简单:

break set pthread_create
break command add 1.1
  bt
  continue
  DONE

但是,我还想打印每次调用此函数的结果(最好在 bt 之后)。

实际上,我基本上想替换实现

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

到:

  • 运行原pthread_create
  • 显示thread的值;
  • 显示回溯;
  • 照常从pthread_create返回。

lldb 会让我这样做吗?

【问题讨论】:

    标签: lldb


    【解决方案1】:

    此问题的另一个解决方案是创建一个自定义步骤类型来满足您的需求。

    中的最后一个例子(FinishPrintAndContinue)

    https://github.com/llvm/llvm-project/blob/master/lldb/examples/python/scripted_step.py

    从当前帧结束,然后打印rax 的值。你可以让它打印你想要的任何东西。

    “完成”完成后示例继续,但您可以通过在您推送的完成计划完成后从“should_stop”返回 True 来更改它。

    你可以通过这样做来使用它:

    (lldb) thread step-scripted -C scripted_step.FinishPrintAndContinue
    

    这有点拗口,不过如果你经常用这个,就给它起个别名吧:

    (lldb) command alias fancy-step thread step-scripted -C scripted-step.FinishPrintAndContinue
    

    那么你可以说:

    (lldb) fancy-step
    

    【讨论】:

      【解决方案2】:

      您可以使用 lldb 的用户定义变量。来自help expression

      用户定义变量:

      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.
      

      在您的示例中,您将创建一个名为$thread 的用户定义变量以供以后使用。然后运行finish(又名thread step-out)来完成pthread_create。此时,运行p $thread 将显示该函数创建的线程。

      生成的断点命令如下所示:

      p pthread_t *$thread = (pthread_t *)$arg1
      finish
      p *$thread
      bt
      continue
      

      $arg1 是用于传递第一个参数的寄存器的 lldb 别名。

      更新

      正如评论中所指出的,在断点命令中使用 finish 会导致“错误:在命令 #2 之后中止读取命令:‘完成’继续目标”。

      一种解决方案是使用 Python 创建一个自定义的finish 命令来避免该问题。此函数运行StepOutOfFrame(),但在此之前它将 lldb 置于同步模式。我已经使用 Xcode 11.3.1 中的 lldb-1100.0.30.12 对此进行了测试。

      import lldb
      
      @lldb.command("Finish")
      def finish(debugger, expression, context, result, _internal):
          is_async = debugger.GetAsync()
          debugger.SetAsync(False)
          context.thread.StepOutOfFrame(context.frame)
          debugger.SetAsync(is_async)
      

      在您的~/.lldbinit 中,导入此脚本:

      command script import path/to/finish.py
      

      现在使用自定义的Finish 命令代替断点命令中的finish(大写名称不会覆盖内置的finish)。

      【讨论】:

      • 谢谢!我需要用= (pthread_t*)$arg1 替换= $arg1。不幸的是,我得到 ``` 错误:在命令 #2 之后中止读取命令:“完成”继续目标。 ```
      • @Yoric 我添加了一个使用 python 的替代完成命令,希望对你有用。
      • 谢谢,它几乎可以工作了:) 我从中学到了很多东西!不幸的是,我意识到我正在寻找的线程 ID 实际上是我从pthread_threadid_np 获得的那个。任何尝试在断点命令中使用它都会导致error: Aborting reading of commands after command #5: 'p (int)pthread_threadid_np(*$thread, &$id)' failed with error: DoExecute called with no thread selected,即使我添加了thread select 1
      猜你喜欢
      • 1970-01-01
      • 2012-10-25
      • 2017-10-19
      • 2021-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-15
      相关资源
      最近更新 更多