在gdb中获取打印表示的输出,并用gdb的printf作为字符串使用它? [英] Getting the output of print representation in gdb, and using it as a string with gdb's printf?

查看:2991
本文介绍了在gdb中获取打印表示的输出,并用gdb的printf作为字符串使用它?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在GDB中使用 print printf 命令有一个区别: print 如果参数是一个对象,可能会打印相关字段,而 printf 严格要求格式说明符和C风格字符串。

There is a difference in using print and printf commands in GDB: print may print related fields if the argument is an object, while printf strictly expects format specifiers and C-style strings.

我想要做的是获取 gdb print 表达式,并将其用作带有%s 格式说明符的字符串数据。通常情况下,这是行不通的 - 使用 test.cpp 程序:

What I'd like to do, is to "get" the output of a gdb print expression, and use it as a string data with a %s format specifier. Usually, that doesn't work - with this test.cpp program:

// g++ --std=c++11 -g test.cpp -o test.exe

#include <iostream>
#include <set>

std::string aa; // just to have reference to std::string

int main()
{
  std::set<std::string> my_set;
  my_set.insert("AA");
  my_set.insert("BB");
  std::cout << "Hello World!" << std::endl;
  return 0;
}

我可以得到如下输出:

I can get output like this:

$ gdb --args ./test.exe
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
...
Breakpoint 1, main () at test.cpp:13
13    std::cout << "Hello World!" << std::endl;
(gdb) p my_set
$1 = std::set with 2 elements = {[0] = "AA", [1] = "BB"}
(gdb) p *my_set
No symbol "operator*" in current context.
(gdb) p my_set->begin()
Cannot resolve method std::set<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::begin to any overloaded instance

...但我不能只使用 my_set 作为 printf 的参数,因为会有一个char数组:

... but I cannot just use my_set as argument of printf, since there a char array would be expected:

(gdb) printf "it is: '%s'\n", my_set
it is: 'Value can't be converted to integer.

那么,是否有可能以某种方式获得打印对象的表示作为一个字符串,用它作为参数 printf ?假设伪代码函数 print_repr(),我想实现这一点:

So, is it possible to somehow obtain the representation of an object of print as a string, to use it as an argument of printf? Assuming pseudocode function print_repr(), I'd like to achieve this:

(gdb) printf "it is: '%s'\n", print_repr(my_set)
it is: '= std::set with 2 elements = {[0] = "AA", [1] = "BB"}'

...并且也希望相同的功能可用于错误,说:

... and also would like the same to function for errors, say:

(gdb) printf "it is: '%s'\n", print_repr(*my_set)
it is: 'No symbol "operator*" in current context.'

这可能吗?

推荐答案

我刚刚使用@TomTromey的指针尝试了这个,但它并不完全无关紧要,所以我发布了这是一个答案,在gdb 7.7.1上测试过。首先,我将它添加到我的〜/ .gdbinit 文件中:

I just tried this using @TomTromey's pointers, but it wasn't exactly trivial, so I'm posting this as an answer, tested on gdb 7.7.1. First, I added this to my ~/.gdbinit file:

python
# https://sourceware.org/gdb/onlinedocs/gdb/Python-API.html#Python-API
# https://sourceware.org/gdb/onlinedocs/gdb/Functions-In-Python.html
class Greet (gdb.Function):
  """Return string to greet someone.
  Takes a name as argument."""
  def __init__ (self):
    super (Greet, self).__init__ ("greet")
  def invoke (self, name):
    return "Hello, %s!" % name.string ()
Greet() # instantiate; then call in gdb: p $greet("myname")

#(gdb) python gdb.execute("p 22")
#$2 = 22

class Strp (gdb.Function):
  """Get a representation of gdb's printout as string
  Argument: the gdb command as string."""
  def __init__ (self):
    super (Strp, self).__init__ ("strp")
  def invoke (self, incmd):
    incmds = str(incmd)
    #print("is",incmds)
    # strip quotes
    if (incmds[0] == incmds[-1]) and incmds.startswith(("'", '"')):
      incmds = incmds[1:-1]
    rets=""
    try:
      rets += gdb.execute(incmds, from_tty=True, to_string=True)
    except Exception as e:
      rets += "Exception: {0}".format(e)
    #print("ret",ret)
    return rets
Strp() # instantiate; then call in gdb: p $strp("p 22")
# quotes end up in arg string, so by default getting Python Exception <class 'gdb.error'> Undefined command: "".  Try "help".: ... but then, if call WITHOUT quotes p $strp(p aa), gdb may interpret "p" as symbol (which doesn't exist) before it is sent as arg to python; therefore, use quotes, then strip them
end

然后,我可以在 gdb

(gdb) p $strp("x 22")
$1 = "Exception: Cannot access memory at address 0x16"
(gdb) p $strp("p 22")
$3 = "$2 = 22\n"
(gdb) p $strp("p aa")
$4 = "Exception: No symbol \"aa\" in current context."
(gdb) printf "%s\n", $strp("p 22")
You can't do that without a process to debug.

因此,常规 gdb p rint不需要一个进程,但是 printf 不会 - 所以在设置断点之后,并且 r gdb 中统一程序/进程,最后可以同时使用Python函数和 printf 在提示符下:

So, the regular gdb print does not need a process, however printf does - so after setting a breakpoint, and running the program/process in gdb, finally one can use both the Python function and printf at the prompt:

Breakpoint 1, main () at /...:17
17  int main( ){
(gdb) printf "%s\n", "aa"
aa
(gdb) printf "%s\n", $strp("p 22")
$12 = 22

(gdb) printf "%s\n", $strp("x 22")
Exception: Cannot access memory at address 0x16
(gdb) printf "%s\n", $strp("p aa")
Exception: No symbol "aa" in current context.
(gdb) printf "%s -- %s\n", $strp("p aa"), $strp("p 22")
Exception: No symbol "aa" in current context. -- $13 = 22

这篇关于在gdb中获取打印表示的输出,并用gdb的printf作为字符串使用它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆