gdbでアセンブルしてSEGVしている箇所を特定するTips

これは-gでコンパイルされていない所でSEGVが発生するときにどの行で落ちているのか見当を付ける方法。
 
こんなコードを用意してみた。
特徴

  • 三つのSEGVの可能性がある関数呼び出しあり
  • もちろん-gでコンパイルしていない
  • 前の記事の使いまわし

 

#Include <stdio.h>
#include <stdlib.h>

struct hoge {
    int id;
    char *comment;
};

void
throw_segv(char *comment)
{
    int test[1000];
    if(!strcmp(comment, "Hellow!")) test[-100000] = 9;
}

int
main(void)
{
    struct hoge *hg;

    hg = malloc(sizeof(struct hoge));
    hg->id = 2565;
    hg->comment = "Hellow!";
    throw_segv("Hoge!");
    throw_segv("Fuge!");
    throw_segv(hg->comment);
    return 1;
}

 
gdbで見てみる。

nari@nari-laptop ~/p/study> gdb debug_test1
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
(gdb) r
Starting program: /home/nari/private/study/debug_test1 

Program received signal SIGSEGV, Segmentation fault.
0x080483c4 in throw_segv ()
Current language:  auto; currently asm

 
バックトレースを覗くと

(gdb) bt
#0  0x080483c4 in throw_segv ()
#1  0x08048429 in main ()

行数がでていない。さて、どの呼び出しで落ちたのか分かるだろうか。
そりゃコードを読めば分かるけど。非常に複雑で入り組んだコードの場合、特定することは非常に困難になる。
(そういう想定で一つ)
 
そこで disassemble ですよ。
0x08048429はバックトレースで出たアドレス。

(gdb) disassemble 0x08048429
Dump of assembler code for function main:
0x080483d0 <main+0>:	lea    0x4(%esp),%ecx
0x080483d4 <main+4>:	and    $0xfffffff0,%esp
0x080483d7 <main+7>:	pushl  -0x4(%ecx)
0x080483da <main+10>:	push   %ebp
0x080483db <main+11>:	mov    %esp,%ebp
0x080483dd <main+13>:	push   %ecx
0x080483de <main+14>:	sub    $0x14,%esp
0x080483e1 <main+17>:	movl   $0x8,(%esp)
0x080483e8 <main+24>:	call   0x80482fc <malloc@plt>
0x080483ed <main+29>:	mov    %eax,-0x8(%ebp)
0x080483f0 <main+32>:	mov    -0x8(%ebp),%eax
0x080483f3 <main+35>:	movl   $0xa05,(%eax)
0x080483f9 <main+41>:	mov    -0x8(%ebp),%eax
0x080483fc <main+44>:	movl   $0x8048500,0x4(%eax)
0x08048403 <main+51>:	movl   $0x8048508,(%esp)
0x0804840a <main+58>:	call   0x80483a4 <throw_segv>
0x0804840f <main+63>:	movl   $0x804850e,(%esp)
0x08048416 <main+70>:	call   0x80483a4 <throw_segv>
0x0804841b <main+75>:	mov    -0x8(%ebp),%eax
0x0804841e <main+78>:	mov    0x4(%eax),%eax
0x08048421 <main+81>:	mov    %eax,(%esp)
0x08048424 <main+84>:	call   0x80483a4 <throw_segv>
0x08048429 <main+89>:	mov    $0x1,%eax
0x0804842e <main+94>:	add    $0x14,%esp
0x08048431 <main+97>:	pop    %ecx
0x08048432 <main+98>:	pop    %ebp
0x08048433 <main+99>:	lea    -0x4(%ecx),%esp
0x08048436 <main+102>:	ret    
End of assembler dump.
(gdb) 

0x08048429を探すと三回目のthrow_segvで落ちている事が分かる。
これはめでたい。