web-dev-qa-db-ja.com

GDB:ジェネリックポインターを逆参照しようとしています

_x/s_のような印刷関数でGDBに追加の逆参照を行わせるにはどうすればよいですか?

_x/_で明示的な逆参照を試みると、「汎用ポインタを逆参照しようとしました」というエラーが表示されます。 _x/_を複数回使用すると機能します。使用するたびに暗黙的な逆参照が含まれるためですが、各中間結果をコピーして貼り付ける必要があるため、これは面倒です。

非常に便利なCプログラム_example.c_を考えてみます。

_#include <stdio.h>
int main(int argc, char **argv) {
  printf("argv[0] = %s\n", argv[0]);
}
_

これをビルドしてGDBにロードすると、argv0xc(%ebp)に格納されていることがわかります。これは、その2つのdererenceが2番目の引数としてprintf(つまり、26行目の0x4(%esp))内:

_$ gcc -o example example.c
$ gdb example

(gdb) disass main
Dump of assembler code for function main:
   0x080483e4 <+0>:   Push   %ebp
   0x080483e5 <+1>:   mov    %esp,%ebp
   0x080483e7 <+3>:   and    $0xfffffff0,%esp
   0x080483ea <+6>:   sub    $0x10,%esp
   0x080483ed <+9>:   mov    0xc(%ebp),%eax
   0x080483f0 <+12>:  mov    (%eax),%edx
   0x080483f2 <+14>:  mov    $0x80484e0,%eax
   0x080483f7 <+19>:  mov    %edx,0x4(%esp)
   0x080483fb <+23>:  mov    %eax,(%esp)
   0x080483fe <+26>:  call   0x8048300 <printf@plt>
   0x08048403 <+31>:  leave  
   0x08048404 <+32>:  ret    
End of assembler dump.
_

printfで中断し、引数firstおよびsecondを指定してプログラムを実行します。

_(gdb) break *main + 26
Breakpoint 1 at 0x80483fe

(gdb) run first second
Starting program: /var/tmp/SO-attempt-to-dereference-generic-pointer/example first second
_

GDBで_argv[0]_を出力しようとしましたが、「汎用ポインタ」エラーが発生します。

_Breakpoint 1, 0x080483e5 in main ()
(gdb) x/s **(0xc + $ebp)
Attempt to dereference a generic pointer.
_

ただし、「x/xw」を使用して手動で数回逆参照すると、最終的に_argv[0]_(および_argv[1]_)を出力できます。

_(gdb) x/xw 0xc + $ebp
0xbfffeba4: 0xbfffec34
(gdb) x/xw 0xbfffec34
0xbfffec34: 0xbfffedc8
(gdb) x/s 0xbfffedc8
0xbfffedc8:  "/var/tmp/SO-attempt-to-dereference-generic-pointer/example"

(gdb) x/xw 0xbfffec34 + 4
0xbfffec38: 0xbfffee03
(gdb) x/s 0xbfffee03
0xbfffee03:  "first"
(gdb) 
_

しかし、これは面倒で間接的です(ポインタプログラミングはそうならないのですか?)

20
ntc2

解決策は、ポインターを逆参照する前にポインターをキャストすることです。

たとえば、上記で中断したところから始めます。

(gdb) x/s **((char ***) (0xc + $ebp))
0xbfffedc8:  "/var/tmp/SO-attempt-to-dereference-generic-pointer/example"
(gdb) x/s *(*((char ***) (0xc + $ebp)) + 1)
0xbfffee03:  "first"
(gdb) x/s *(*((char ***) (0xc + $ebp)) + 2)
0xbfffee09:  "second"

スタックアドレス0xc + $ebpは、それ自体がそのスタックの場所の内容へのポインターであるため、char ***ではなくchar **が必要であることに注意してください。

24
ntc2