簡體   English   中英

如何執行完成,然后從命令內執行另一個命令?

[英]How to execute finish and then another command from inside commands?

這是我的代碼結構的簡化示例:

void increment(int j);

int main()
{
  int i = 0;

  while(1) {
    i = increment(i);
  }

  return 0;
}

int increment(int j)
{
  return j + 1;
}

這是相應的GDB腳本:

b increment
command 1
finish
print i
continue
end

問題是finish命令阻止了之后的命令(即print icontinue )不被調用。

有沒有辦法來告訴GDB打印i的任何之后increment電話嗎?

您可以通過將所有命令包裝在單個python調用中來解決此錯誤,例如

(gdb) break doSomething
Breakpoint 1 at 0x400478: file iter.c, line 5.
(gdb) commands
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>python gdb.execute("print i"); gdb.execute("finish"); gdb.execute("print i");
>end

Breakpoint 1, doSomething () at iter.c:5
5     while (i < 5)
$1 = 0
main (argc=1, argv=0x7fffffffe178) at iter.c:13
13    return 0;
$2 = 5

編輯:第二個解決方法不需要python似乎是定義一個新的gdb命令並在命令中運行它:

define foo
print *i
set $addrOfI = i
finish
print *$addrOfI
end

break doSomething
commands
foo
end

問題是,完成似乎停止中止為其后的第一個斷點設置的命令。

這是預期的行為:任何恢復下級(正在調試)進程的命令(如finish )也會停止執行固定命令序列。

更新:

另請參閱此GDB錯誤報告

有沒有辦法告訴GDB在任何增量調用后立即打印?

是:

  1. 使用disas命令進行Diassemble increment例程。 在它的末尾找到ret指令(只有一個)。
  2. 使用break *0xNNNNN語法在該指令上設置斷點。
  3. 將命令附加到該斷點:

     command N print $rax # or $eax if you are on 32-bit x86 platform continue end 

Voila:你應該從increment()打印返回的值(就在返回之前)。

或者@Matt回答,如果你使用GDB 7.4,你可以使用FinishBreakpoints,類似於(未經測試 - 我不確定這里是否接受評論):

(gdb) python #first defined the class
class MyFinishBreakpoint (gdb.FinishBreakpoint):
    def stop (self):
        print "%s" % gdb.parse_and_eval("i")
        return False # don't want to stop
end
(gdb) break doSomething
(gdb) commands
# then set the FinishBreakpoint silently
silent
py MyFinishBreakpoint()
continue

(以及文檔的鏈接)

你真的試過編譯嗎? 您的increment()函數聲明為void ,但需要為int 改變之后,它對我來說很好:

% gdb test
GNU gdb (Ubuntu/Linaro 7.3-0ubuntu2) 7.3-2011.08
[...]
Reading symbols from test...done.
(gdb) b increment 
Breakpoint 1 at 0x4004bb: file test.c, line 5.
(gdb) r
Starting program: test 

Breakpoint 1, increment (j=0) at test.c:5
5               return j+1;
(gdb) fin
Run till exit from #0  increment (j=0) at test.c:5
0x00000000004004dc in main () at test.c:11
11                      i = increment(i);
Value returned is $1 = 1
(gdb) n
12              }
(gdb) p i
$2 = 1
(gdb)

GDB斷點命令列表受到限制,因為它們在第一個步進/繼續命令之后忽略任何命令(截至2017年3月,GDB 7.12)。 在GDB手冊中有記載,其中當前的實現不能同時執行兩個命令列表(參見GDB#10852 - 命令序列意外中斷 )。

只有在命令列表中直接出現的步進/繼續命令才會強制執行此限制。 因此,人們可以解決這個問題 - 但是限制仍然適用,例如GDB手冊在Python API部分中警告 :'你不應該改變下級的執行狀態(即步驟,下一步等)

因此,當需要在函數入口函數退出時執行GDB命令時,可靠的解決方案是使用多個斷點並拆分命令列表。 這意味着需要為正在調查的函數的每個返回指令設置額外的斷點。

這可以類似於:

(gdb) b my_function
(gdb) commands
silent
printf "my_function: %d -> ", j
end
(gdb) set pagination off
(gdb) set logging file gdb.log
(gdb) set logging overwrite on
(gdb) set logging on
(gdb) disas my_function
(gdb) set logging off
(gdb) shell grep ret gdb.log
0x00007ffff76ad095 <+245>:  retq
(gdb) b *0x00007ffff76ad095
(gdb) commands
silent
printf "%lu\n", $rax
end

包含返回值的寄存器取決於調用約定,並且取決於體系結構。 x86-64上它是 $rax 其他選擇是x86-32上的$eax ,SPARC上的$o0 ,ARM上的$r0等。

可以使用其腳本支持在GDB中自動創建其他斷點。

蟒蛇

最近的GDB版本附帶了一個非常適合這種自動化的Python API 發行版提供的GDB包通常默認啟用Python支持。

作為第一個示例,在給定函數的每個ret指令上自動設置斷點:

(gdb) py fn='myfunc'; list(map(lambda l: gdb.execute('b *{}'.format(l[0])), \
    filter(lambda l : l[2].startswith('ret'), map(lambda s : s.split(), \
        gdb.execute('disas '+fn, to_string=True).splitlines()))))

(假設GDB是用Python3支持編譯的,例如Fedora 25一個)

為了自動創建打印返回值的斷點(即register $rax的值),然后繼續gdb.Breakpoint需要進行子類化:

py
class RBP(gdb.Breakpoint):
  def stop(self):
    print(gdb.parse_and_eval('$rax'))
    return False

end

然后可以像這樣創建一個斷點:

py RBP('*0x000055555555894e')

結合創建新自定義命令的兩個步驟:

py
class Pret_Cmd(gdb.Command):
  '''print return value via breakpoint command

  pret FUNCTION
  '''
  def __init__(self):
    super().__init__('pret', gdb.COMMAND_BREAKPOINTS)

  def install(self, fn):
    for l in filter(lambda l : l[2].startswith('ret'),
        map(lambda s : s.split(),
            gdb.execute('disas '+fn, to_string=True).splitlines())):
      RBP('*{}'.format(l[0]))

  def invoke(self, arg, from_tty):
    self.install(arg)

Pret_Cmd()
end

使用此新命令的示例:

(gdb) help breakpoints
(gdb) help pret
(gdb) pret myfunc

詭計

如果你不喜歡Python和/或有一個禁用Python支持的GDB - 但啟用了Guile支持 - 你也可以通過Guile自動設置斷點。

Guile中的自定義命令定義:

(gdb) gu (use-modules (gdb))
(gdb) gu
(register-command!
  (make-command "pret" #:command-class COMMAND_BREAKPOINTS #:doc
    "print return value via breakpoint command\n\npret FUNCTION"
    #:invoke
    (lambda (fn)
      (map (lambda (x)
             (let ((bp (make-breakpoint (string-append "*" x))))
               (register-breakpoint! bp)
               (set-breakpoint-stop!
                 bp
                 (lambda (x)
                   (display (parse-and-eval "$rax"))
                   (newline)
                   #f))
               bp))
           (map (lambda (x) (list-ref x 0))
                (filter
                  (lambda (x)
                    (and (not (null? x))
                         (string-prefix? "ret" (list-ref x 2))))
                  (map (lambda (x) (string-tokenize x))
                       (string-split
                         (execute
                           (string-append "disas " fn)
                           #:to-string
                           #t)
                         #\newline))))))))

end

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM