Chinaunix首页 | 论坛 | 博客
  • 博客访问: 494147
  • 博文数量: 133
  • 博客积分: 1235
  • 博客等级: 少尉
  • 技术积分: 1201
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-08 19:59
文章分类

全部博文(133)

文章存档

2023年(12)

2022年(3)

2018年(2)

2017年(4)

2016年(4)

2015年(42)

2014年(1)

2013年(12)

2012年(16)

2011年(36)

2010年(1)

分类: 其他平台

2015-04-29 15:22:16

Tool GDB

Examining Memory (data or in machine instructions)

You can use the command x (for “examine”) to examine memory in any of several formats, independently of your program's data types.

x/nfu addr

x addr

x

n, the repeat count

The repeat count is a decimal integer; the default is 1. It specifies how much memory (counting by units u) to display.

f, the display format

The display format is one of the formats used by print (`x', `d', `u', `o', `t', `a', `c', `f', `s'), and in addition `i' (for machine instructions). The default is `x' (hexadecimal) initially. The default changes each time you use either x or print.

x -- Print as integer in hexadecimal.

d -- Print as integer in signed decimal.

u -- Print as integer in unsigned decimal.

o -- Print as integer in octal.

t -- Print as integer in binary. The letter `t' stands for “two”. 1

a -- Print as an address, both absolute in hexadecimal and as an offset from the nearest preceding symbol. You can use this format used to discover where (in what function) an unknown address is located:

          (gdb) p/a 0x54320

          $3 = 0x54320 <_initialize_vx+396>

c -- Regard as an integer and print it as a character constant.

f -- Regard as a floating point number and print using typical floating point syntax.

s --Regard as a string

u, the unit size  -- The unit size is any of

b -- Bytes.

h -- Halfwords (two bytes).

w -- Words (four bytes). This is the initial default.

g -- Giant words (eight bytes).

Each time you specify a unit size with x, that size becomes the default unit the next time you use x. For the `i' format, the unit size is ignored and is normally not written. For the `s' format (string), the unit size defaults to `b', unless it is explicitly given. Use x /hs to display 16-bit char strings and x /ws to display 32-bit strings. The next use of x /s will again display 8-bit strings. Note that the results depend on the programming language of the current compilation unit. If the language is C, the `s' modifier will use the UTF-16 encoding while `w' will use UTF-32. The encoding is set by the programming language and cannot be altered.

Example:

x/4xw $sp -- print the four words (`w') of memory above the stack pointer  in hexadecimal (`x').

x/3uh 0x54320 -- display three halfwords (h) of memory, formatted as unsigned decimal integers (`u'), starting at address 0x54320.

x/5i $pc-6 -- examines machine instructions.

Registers

The names of registers are different for each machine; use info registers to see the names 
used on your machine.
info registers– check register names
gdb four “standard” register:
$pc -- the program counter register, $RIP
$sp -- the stack pointer register, $RSP
$fp -- a pointer to the current stack frame, “base pointer” register, $RBP
$ps -- a register that contains the processor status
Example:
p/x $pc
x/i $pc

GDB conversation

If displaying variable, which is a address, gdb will try to display its content(value) together. 
Format: 
Address:  content(value) 
Example:
(gdb) x/x $pc  -- $pc is a address
0x40071e <_Z3addii+4>:  0x10ec8348
(gdb) x/i $pc
0x40071e <_Z3addii+4>:  sub    $0x10,%rsp
(gdb) x/xg $pc
0x40071e <_Z3addii+4>:  0x89fc7d8910ec8348
(gdb) p $pc – print value of $pc only
$9 = (void (*)()) 0x40071e 
(gdb) p/x $pc
$10 = 0x40071e 

Advance guide for debugging a program

Introduce

Any program only includes data and machine instructions.
Machine instructions: user code(Text), static lib code and shared lib code. We can 
disassemble program at any program memory. 
Data: initialized data, uninitialized data (bss), Heap(malloc arena), stack and registers. 
Commonly, the code(machine instruction) won’t change when running a program. It means 
if we track data, we can know the all program status according to machine instruction. 
This means gdb x command can be a general tool for program debug.

Virtual memory

Modern operating systems and architectures provide virtual memory. Through hardware support and additional code in the operating system, virtual memory allows each user process to act as though it is the only thing running on the computer. It gives each process a completely separate address space.

Through pmap, user can check process' memory map, such as:

$ pmap 23814  # If you don't have pmap installed, use 'cat /proc/23814/maps'

Process memory layout

 

It is for 64-bit systems. On 32-bit systems the shared libraries are usually found at the lowest address, followed by the text segment, then everything else.

The text, or code, segment contains the actual program and any statically linked libraries. On 64-bit systems it generally starts at 0x400000 (32-bit systems like to place it at 0x8047000).

The data and BSS segments come next. The data segment contains all initialized global variables as well as static strings (eg, those used in printf). The BSS, or "block started by segment" region holds all uninitialized global variables (those which by C convention are initialized automatically to 0).

After that comes the heap, where all memory obtained via malloc() is located. The heap grows upwards as more memory is requested.

Then we have any shared libraries such as the loader, libc, malloc, etc.

Finally we have the stack, which it should be noted grows downward as it expands.

Downward-growing stack

Programs use the stack to store temporary, or automatic variables, arguments passed during a function call, and information needed to return to a previous point in the program when a function call is made.

There are also three registers that are important at this point - RBP, RSP, and RIP. RSP is the stack pointer. The stack works just like a LIFO queue with push() and pop() operations. RSP tracks the next available position in this queue.

The stack frame is essentially the region of the stack that is presently active, or that corresponds to the presently executing function. It is pointed to by RBP, the "base pointer," and is used in combination with an offset to reference all local variables. Every time a function is called, RBP is updated to point to its stack frame.  

RIP is the instruction pointer. It holds the address of the instruction that the CPU just loaded and is presently executing.

The diagram above shows a snapshot of the stack for a program that is presently in func1(), which was called from main(). In order for the stack to look this way, some things must have happened when func1() was called. These steps are defined by the C calling convention. 

1. The arguments to func1() were pushed onto the stack.
2. func1() was called.
3. RBP was pushed onto the stack.
4. RSP was moved to RBP.
5. Space for the local variables was allocated on the stack.
6. Local variables were set to initial values (if provided).

Steps 3 through 6 are called the function prelude.

图3 带有基指针的栈帧

System calls

The only way to enter supervisor mode is to go through predefined entry points in the kernel. 
One of these points is called a system call.

How system calls work on x86_64 Linux by taking a look at the kernel source, specifically arch/x86_64/kernel/entry.S where we see the following comment...

/*

 * System call entry. Upto 6 arguments in registers are supported.

 *

 * SYSCALL does not save anything on the stack and does not change the

 * stack pointer.

 */

                              

/*

 * Register setup: 

 * rax  system call number

 * rdi  arg0

 * rcx  return address for syscall/sysret, C arg3

 * rsi  arg1

 * rdx  arg2        

 * r10  arg3        (--> moved to rcx for C)

 * r8   arg4

 * r9   arg5

 * r11  eflags for syscall/sysret, temporary for C

 * r12-r15,rbp,rbx saved by C code, not touched.                          

 *

 * Interrupts are off on entry.

 * Only called from user space.

 *

 * XXX   if we had a free scratch register we could save the RSP into the stack frame

 *      and report it properly in ps. Unfortunately we haven't.

 */                                                                     

So to make a system call, you first store the syscall number in RAX, any parameters in RDI, RSI, 
RDX, etc, and then execute the "syscall" instruction.

 

图4 64位模式下通用寄存器的大小和名称

 

图5 在传统和兼容模式下的通用寄存器大小和名称

通用寄存器在编程时通常用于不同的用途,说明如表1所示。

表1 通用寄存器的用途

寄存器名

用途

EAX

累加器

EBX

基址寄存器

ECX

计数器

EDX

数据寄存器

ESI

源地址指针寄存器

EDI

目的地址指针寄存器

EBP

基址指针寄存器

ESP

堆栈指针寄存器

 

Example

 

Test ENV

 

nochen@bclnx64 ~/test$ uname -a

Linux bclnx64 2.6.9-34.ELsmp #1 SMP Thu Mar 9 06:23:23 GMT 2006 x86_64 x86_64 x86_64 GNU/Linux

nochen@bclnx64 ~/test$ g++ -v

Reading specs from /usr/lib/gcc/x86_64-redhat-linux/3.4.5/specs

Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-java-awt=gtk --host=x86_64-redhat-linux

Thread model: posix

gcc version 3.4.5 20051201 (Red Hat 3.4.5-2)

nochen@bclnx64 ~/test$ gdb -v

GNU gdb Red Hat Linux (6.3.0.0-1.96rh)

Copyright 2004 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB.  Type "show warranty" for details.

This GDB was configured as "x86_64-redhat-linux-gnu".

 

Example 1

 

Aim: basic stack usage, basic assemble code

#include 

#include 

#include 

#include 

 

int Add(int a, int b, int c){

    int arr[4] = {0};

    arr[0] = a;

    arr[1] = b;

    arr[2] = c;

 

    arr[3] = a+b+c;

    return arr[3];

}

 

int main() {

    int a = 0x100;

    int b = 0x200;

    int c = 0x345;

 

    Add(a,b,c);

    return 1;

}

 

 

  gdb ./test

(gdb) x/40i Add-2

0x400506 :      nop

0x400507 :      nop

0x400508 <_Z3Addiii>:   push   %rbp

0x400509 <_Z3Addiii+1>: mov    %rsp,%rbp

0x40050c <_Z3Addiii+4>: mov    %edi,0xfffffffffffffffc(%rbp)

0x40050f <_Z3Addiii+7>: mov    %esi,0xfffffffffffffff8(%rbp)

0x400512 <_Z3Addiii+10>:        mov    %edx,0xfffffffffffffff4(%rbp)

0x400515 <_Z3Addiii+13>:        movq   $0x0,0xffffffffffffffe0(%rbp)

0x40051d <_Z3Addiii+21>:        movq   $0x0,0xffffffffffffffe8(%rbp)

0x400525 <_Z3Addiii+29>:        mov    0xfffffffffffffffc(%rbp),%eax

0x400528 <_Z3Addiii+32>:        mov    %eax,0xffffffffffffffe0(%rbp)

0x40052b <_Z3Addiii+35>:        mov    0xfffffffffffffff8(%rbp),%eax

0x40052e <_Z3Addiii+38>:        mov    %eax,0xffffffffffffffe4(%rbp)

0x400531 <_Z3Addiii+41>:        mov    0xfffffffffffffff4(%rbp),%eax

0x400534 <_Z3Addiii+44>:        mov    %eax,0xffffffffffffffe8(%rbp)

0x400537 <_Z3Addiii+47>:        mov    0xfffffffffffffff8(%rbp),%eax

0x40053a <_Z3Addiii+50>:        add    0xfffffffffffffffc(%rbp),%eax

0x40053d <_Z3Addiii+53>:        add    0xfffffffffffffff4(%rbp),%eax

0x400540 <_Z3Addiii+56>:        mov    %eax,0xffffffffffffffec(%rbp)

0x400543 <_Z3Addiii+59>:        mov    0xffffffffffffffec(%rbp),%eax

0x400546 <_Z3Addiii+62>:        leaveq

0x400547 <_Z3Addiii+63>:        retq

0x400548 

:        push   %rbp

0x400549 :      mov    %rsp,%rbp

0x40054c :      sub    $0x10,%rsp

0x400550 :      movl   $0x100,0xfffffffffffffffc(%rbp)

0x400557 :     movl   $0x200,0xfffffffffffffff8(%rbp)

0x40055e :     movl   $0x345,0xfffffffffffffff4(%rbp)

0x400565 :     mov    0xfffffffffffffff4(%rbp),%edx

0x400568 :     mov    0xfffffffffffffff8(%rbp),%esi

0x40056b :     mov    0xfffffffffffffffc(%rbp),%edi

0x40056e :     callq  0x400508 <_Z3Addiii>

0x400573 :     mov    $0x1,%eax

0x400578 :     leaveq

0x400579 :     retq

0x40057a :     nop

(gdb) b Add

Breakpoint 1 at 0x400515: file stack2.cc, line 20.

(gdb) r

Starting program: /home/nochen/test/test

Breakpoint 1, Add (a=256, b=512, c=837) at stack2.cc:20

20                        int arr[4] = {0};

(gdb) info register

rax            0x645    1605

rbx            0x0      0

rcx            0x20     32

rdx            0x345    837

rsi            0x200    512

rdi            0x100    256

rbp            0x7fbffff480     0x7fbffff480

rsp            0x7fbffff480     0x7fbffff480

r8             0x7fbffff4d0     548682069200

rip            0x400543 0x400543 

eflags         0x302    770

(gdb) x/60gx $sp-32

0x7fbffff460:   0x0000020000000100      0x0000064500000345

0x7fbffff470:   0x00000345f5614c40      0x0000010000000200 // Add()ocal variables

0x7fbffff480:   0x0000007fbffff4a0      0x0000000000400573 //current rbp - last rbp - ret add

0x7fbffff490:   0x0000034500000000      0x0000010000000200 //main()ocal variables

0x7fbffff4a0:   0x0000003cf5b31738      0x0000003cf591c4bb //main rbp

0x7fbffff4b0:   0x0000000000400450      0x0000007fbffff578

0x7fbffff4c0:   0x0000000100000000      0x0000000000400548

 

Example 2

 

Aim: basic stack usage, basic assemble code

 

#include 

#include 

#include 

#include 

 

int Add(int a, int b, int c){

    return a+b+c;

}

 

int main() {

    int a = 0x100;

    int b = 0x200;

    int c = 0x345;

 

    Add(a,b,c);

    return 1;

}

 

gdb ./test

(gdb) x/40i Add

0x400508 <_Z3Addiii>:   push   %rbp

0x400509 <_Z3Addiii+1>: mov    %rsp,%rbp

0x40050c <_Z3Addiii+4>: mov    %edi,0xfffffffffffffffc(%rbp)

0x40050f <_Z3Addiii+7>: mov    %esi,0xfffffffffffffff8(%rbp)

0x400512 <_Z3Addiii+10>:        mov    %edx,0xfffffffffffffff4(%rbp)

0x400515 <_Z3Addiii+13>:        mov    0xfffffffffffffff8(%rbp),%eax

0x400518 <_Z3Addiii+16>:        add    0xfffffffffffffffc(%rbp),%eax

0x40051b <_Z3Addiii+19>:        add    0xfffffffffffffff4(%rbp),%eax

0x40051e <_Z3Addiii+22>:        leaveq

0x40051f <_Z3Addiii+23>:        retq

0x400520 

:        push   %rbp

0x400521 :      mov    %rsp,%rbp

0x400524 :      sub    $0x10,%rsp

0x400528 :      movl   $0x100,0xfffffffffffffffc(%rbp)

0x40052f :     movl   $0x200,0xfffffffffffffff8(%rbp)

0x400536 :     movl   $0x345,0xfffffffffffffff4(%rbp)

0x40053d :     mov    0xfffffffffffffff4(%rbp),%edx

0x400540 :     mov    0xfffffffffffffff8(%rbp),%esi

0x400543 :     mov    0xfffffffffffffffc(%rbp),%edi

0x400546 :     callq  0x400508 <_Z3Addiii>

0x40054b :     mov    $0x1,%eax

0x400550 :     leaveq

0x400551 :     retq

0x400552 :     nop

(gdb) b Add

Breakpoint 1 at 0x400515: file stack2.cc, line 29.

(gdb) r

The program being debugged has been started already.

Start it from the beginning? (y or n) y

Starting program: /home/nochen/test/test

 

Breakpoint 1, Add (a=256, b=512, c=837) at stack2.cc:29

29          return a+b+c;

(gdb) info register

rax            0x0      0

rbx            0x0      0

rcx            0x20     32

rdx            0x345    837

rsi            0x200    512

rdi            0x100    256

rbp            0x7fbffff480     0x7fbffff480

rsp            0x7fbffff480     0x7fbffff480

r8             0x7fbffff4d0     548682069200

rip            0x400515 0x400515 

eflags         0x206    518

 (gdb) s

30      }

(gdb) x/16gx 0x7fbffff480-32

0x7fbffff460:   0x0000003cf87dfb00      0x0000000000000000

0x7fbffff470:   0x00000345f5614c40      0x0000010000000200

0x7fbffff480:   0x0000007fbffff4a0      0x000000000040054b

0x7fbffff490:   0x0000034500000000      0x0000010000000200

0x7fbffff4a0:   0x0000003cf5b31738      0x0000003cf591c4bb

0x7fbffff4b0:   0x0000000000400450      0x0000007fbffff578

0x7fbffff4c0:   0x0000000100000000      0x0000000000400520

0x7fbffff4d0:   0x0000000000000000      0x0000003cf5614c40

Example 3

 

Aim: a case for crashing stack

#include 

 

 

 

int main (int argc, char** argv ) {

 

  execve("/bin/sh", NULL, NULL); // correct: execve("/bin/sh", argv, NULL);

 

}

 

 

gdb ./test

(gdb) disassemble main

Dump of assembler code for function main:

0x0000000000400570 :    push   %rbp

0x0000000000400571 :    mov    %rsp,%rbp

0x0000000000400574 :    sub    $0x10,%rsp

0x0000000000400578 :    mov    %edi,0xfffffffffffffffc(%rbp)

0x000000000040057b :   mov    %rsi,0xfffffffffffffff0(%rbp)

0x000000000040057f :   mov    $0x0,%edx

0x0000000000400584 :   mov    $0x0,%esi

0x0000000000400589 :   mov    $0x40068c,%edi

0x000000000040058e :   callq  0x400480 // Use disassemble execveto get execve code  // a little different with: 0x400480

0x0000000000400593 :   mov    $0x1,%eax

0x0000000000400598 :   leaveq

0x0000000000400599 :   retq

End of assembler dump.

(gdb) r

Starting program: /home/nochen/test/test

 

Program received signal SIGSEGV, Segmentation fault.

0x0000000000418969 in ?? ()

(gdb) bt

#0  0x0000000000418969 in ?? ()

#1  0x0000000000000000 in ?? ()

(gdb) info register

rax            0x0      0

rbx            0x0      0

rcx            0x3cf592e813     261818083347

rdx            0x0      0

rsi            0x0      0

rdi            0x0      0

rbp            0x5b4870 0x5b4870  // rbp is wrong. I think Stack crash

rsp            0x7fbffffbb0     0x7fbffffbb0

rip            0x418969 0x418969

eflags         0x10246  66118

 (gdb) x/16gx 0x5b4870-16

0x5b4860:       0x0000003cf5b2e680      0x0000000000000000

0x5b4870:       0x0000007fbffffee0      0x0000003cf5b2eb00

0x5b4880:       0x0000000000000000      0x0000000000000000

0x5b4890:       0x0000003cf5b2e8c0      0x0000000000000000

0x5b48a0:       0x0000000000000000      0x0000000000000000

0x5b48b0:       0x0000000000000000      0x0000000000000000

0x5b48c0:       0x0000000000000000      0x0000000000000000

0x5b48d0:       0x0000000000000000      0x0000000000000000

(gdb) x/16gx 0x0000007fbffffee0-16

0x7fbffffed0:   0x0000000000000000      0x0000000000000000

0x7fbffffee0:   0x0000000000000000      0x0000000000000010 // wrong last rbp addr

0x7fbffffef0:   0x00000000bfebfbff      0x0000000000000006

0x7fbfffff00:   0x0000000000001000      0x0000000000000011

0x7fbfffff10:   0x0000000000000064      0x0000000000000003

0x7fbfffff20:   0x0000000000400040      0x0000000000000004

0x7fbfffff30:   0x0000000000000038      0x0000000000000005

0x7fbfffff40:   0x0000000000000009      0x0000000000000007

(gdb) x/16i 0x0000000000418969-8

0x418961:       add    %cl,0xffffffffffffff89(%rax)

0x418964:       add    $0x19bf4f,%eax

0x418969:       cmpb   $0x2d,(%rax)

0x41896c:       je     0x418c46

0x418972:       mov    1687359(%rip),%rdx        # 0x5b48b8

0x418979:       cmpb   $0x73,(%rdx)

0x41897c:       je     0x418c21

0x418982:       mov    1687343(%rip),%rdx        # 0x5b48b8

0x418989:       cmpb   $0x73,(%rdx)

0x41898c:       je     0x418bfa

0x418992:       mov    1705607(%rip),%rdi        # 0x5b9020

0x418999:       mov    %rbx,1687320(%rip)        # 0x5b48b8

0x4189a0:       test   %rdi,%rdi

0x4189a3:       jne    0x418bee

0x4189a9:       mov    1687304(%rip),%rdi        # 0x5b48b8

0x4189b0:       callq  0x417380

(gdb)

For this case, I don't know how to debug it accord to these information!

Example 4

 

Aim: for dead-lock case. 

#include 

#include 

#include 

#include 

#include 

 

pthread_t ntid;

 

class Mutex

{

public:

    Mutex(bool recursive = false) {

    pthread_mutexattr_t attr;

    pthread_mutexattr_init(&attr);

    pthread_mutexattr_settype(&attr,

        recursive ?  PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_ERRORCHECK );

    pthread_mutex_init(&d_mutex, &attr);

    pthread_mutexattr_destroy(&attr);

    }

    ~Mutex() { pthread_mutex_destroy(&d_mutex); }

 

    void Lock() { pthread_mutex_lock(&d_mutex); }

    void Lock_Cancel() {  pthread_testcancel(); pthread_mutex_lock(&d_mutex); }

    void Unlock() { pthread_mutex_unlock(&d_mutex); }

    bool TryLock() { return pthread_mutex_trylock(&d_mutex) == 0; }

 

private:

    pthread_mutex_t d_mutex;

};

 

void printids(const char *s)

{

    pid_t       pid;

    pthread_t   tid;

 

    pid = getpid();

    tid = pthread_self();

    printf("%s pid %u tid %u (0x%x)\n", s, (unsigned int)pid,

            (unsigned int)tid, (unsigned int)tid);

}

 

Mutex locker, locker2;

 

void * thr_fn(void *arg)

{

    int count = 1000;

    if(arg != NULL)

        count = *((int*)arg);

 

    locker.Lock();

    int i=0;

    for(i=0; i

    {

        printf("Func 1 Time %d : ", i);

        locker2.Lock();

        printids("new thread: ");

        sleep(1);

        locker2.Unlock();

    }

 

    locker.Unlock();

    return((void *)0);

}

 

int main(void)

{

    int err;

    pthread_t tid1, tid2;

    void* tret;

 

    int count = 10;

 

    printf("PID=%d\n", getpid());

    // thread 1

    err = pthread_create(&tid1, NULL, thr_fn, NULL);

    if (err != 0)

    {

        printf("can't create thread : %s\n", strerror(err));

    }

    printf("Create thread 1 : %u \n", (unsigned int)tid1);

 

    // thread 2

    err = pthread_create(&tid2, NULL, thr_fn, &count);

    if (err != 0)

    {

        printf("can't create thread : %s\n", strerror(err));

    }

    printf("Create thread 2 : %u \n", (unsigned int)tid2);

 

    printids("main thread:");

    sleep(1);

 

    pthread_cancel(tid1);

    printf("Cancel thread 1\n");

 

    err = pthread_join(tid1, &tret);

    if (err != 0)

        printf("can't join with thread 1: %s\n", strerror(err));

 

printf("thread 1 exit code %d\n", (int)tret);

    err = pthread_join(tid2, &tret);

    if (err != 0)

        printf("can't join with thread 2: %s\n", strerror(err));

 

    printf("thread 2 exit code %d\n", (int)tret);

 

    return 0;

}

 

 

g++ -o test deadlock.cc lpthread

(shell 1)nochen@bclnx64 ~/test$ ./test  

PID=4249

Create thread 1 : 1084229984

Create thread 2 : 1094719840

main thread: pid 4249 tid 2505602208 (0x955874a0)

Func 1 Time 0 : new thread:  pid 4249 tid 1084229984 (0x40a00960)

Cancel thread 1

thread 1 exit code -1

 

(shell 2)gdb ./test

(gdb) attach 4249

(gdb) info thread

  2 Thread 1094719840 (LWP 4251)  0x0000003cf620adfb in __lll_mutex_lock_wait () from /lib64/tls/libpthread.so.0

  1 Thread 182894228640 (LWP 4249)  0x0000003cf6206ffb in pthread_join () from /lib64/tls/libpthread.so.0

(gdb) bt

#0  0x0000003cf6206ffb in pthread_join () from /lib64/tls/libpthread.so.0

#1  0x0000000000400d8e in main ()

(gdb) thread 2

[Switching to thread 2 (Thread 1094719840 (LWP 4251))]#0  0x0000003cf620adfb in __lll_mutex_lock_wait ()

   from /lib64/tls/libpthread.so.0

(gdb) bt

#0  0x0000003cf620adfb in __lll_mutex_lock_wait () from /lib64/tls/libpthread.so.0

#1  0x00000000414011e0 in ?? ()

#2  0x00000000414019f0 in ?? ()

#3  0x0000003cf6207bd4 in pthread_mutex_lock () from /lib64/tls/libpthread.so.0

#4  0x0000000000000000 in ?? ()

(gdb) info register

rax            0xfffffffffffffffc       -4

rbx            0x0      0

rcx            0xffffffffffffffff       -1

rdx            0x2      2

rsi            0x0      0

rdi            0x501740 5248832

rbp            0x414011b0       0x414011b0

rsp            0x41401100       0x41401100

rip            0x3cf620adfb     0x3cf620adfb <__lll_mutex_lock_wait+27>

eflags         0x202    514

 (gdb) x/16gx 0x414011b0 - 16

0x414011a0:     0x0000000000000000      0x0000000000501740

0x414011b0:     0x00000000414011d0      0x0000000000400b4d

0x414011c0:     0x0000000a00000000      0x0000007fbffff3cc

0x414011d0:     0x0000000000000000      0x0000003cf620610a (not useful information)

0x414011e0:     0x0000000000000000      0x0000000041401960

0x414011f0:     0x0000000041401960      0x0000000000000000

0x41401200:     0x0000003cf6206080      0x0000003cf620d4e0

0x41401210:     0x0000000000000000      0x0000003cf620d4e0

(gdb) x/32i 0x0000000000400b4d - 4

0x400b49 <_Z6thr_fnPv+41>:      push   %rbx

0x400b4a <_Z6thr_fnPv+42>:      add    (%rax),%eax

0x400b4c <_Z6thr_fnPv+44>:      add    %al,%bh

0x400b4e <_Z6thr_fnPv+46>:      rexXZ lock add %al,(%rax)

0x400b52 <_Z6thr_fnPv+50>:      add    %al,(%rax)

0x400b54 <_Z6thr_fnPv+52>:      movl   $0x0,0xfffffffffffffff0(%rbp)

0x400b5b <_Z6thr_fnPv+59>:      mov    0xfffffffffffffff0(%rbp),%eax

0x400b5e <_Z6thr_fnPv+62>:      cmp    0xfffffffffffffff4(%rbp),%eax

0x400b61 <_Z6thr_fnPv+65>:      jge    0x400ba5 <_Z6thr_fnPv+133>

0x400b63 <_Z6thr_fnPv+67>:      mov    0xfffffffffffffff0(%rbp),%esi

0x400b66 <_Z6thr_fnPv+70>:      mov    $0x401035,%edi

0x400b6b <_Z6thr_fnPv+75>:      mov    $0x0,%eax

 

From these information, we can know that the dead-lock is in function thr_fnPv+44 and thr_fnPv+46。 Thus we know it is because thread 2(1094719840) cant get lock!

 

Example 5

 

Aim: for dead-lock case. 

#include 

#include 

#include 

#include 

#include 

 

pthread_t ntid;

 

class Mutex

{

public:

    Mutex(bool recursive = false) {

    pthread_mutexattr_t attr;

    pthread_mutexattr_init(&attr);

    pthread_mutexattr_settype(&attr,

        recursive ?  PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_ERRORCHECK );

    pthread_mutex_init(&d_mutex, &attr);

    pthread_mutexattr_destroy(&attr);

    }

    ~Mutex() { pthread_mutex_destroy(&d_mutex); }

 

    void Lock() { pthread_mutex_lock(&d_mutex); }

    void Lock_Cancel() {  pthread_testcancel(); pthread_mutex_lock(&d_mutex); }

    void Unlock() { pthread_mutex_unlock(&d_mutex); }

    bool TryLock() { return pthread_mutex_trylock(&d_mutex) == 0; }

 

private:

    pthread_mutex_t d_mutex;

};

 

void printids(const char *s)

{

    pid_t       pid;

    pthread_t   tid;

 

    pid = getpid();

    tid = pthread_self();

    printf("%s pid %u tid %u (0x%x)\n", s, (unsigned int)pid,

            (unsigned int)tid, (unsigned int)tid);

}

 

Mutex locker, locker2;

 

void * thr_fn(void *arg)

{

    int count = 1000;

    if(arg != NULL)

        count = *((int*)arg);

 

    locker.Lock();

    int i=0;

    for(i=0; i

    {

        printf("Func 1 Time %d : ", i);

        locker2.Lock();

        printids("new thread: ");

        sleep(1);

        locker2.Unlock();

    }

 

    locker.Unlock();

    return((void *)0);

}

 

 

void * thr_fn2(void *arg)

{

    int count = 1000;

    if(arg != NULL)

        count = *((int*)arg);

 

    locker2.Lock();

    int i=0;

    for(i=0; i

    {

        printf("Func2 Time %d : ", i);

        locker.Lock();

        printids("new thread: ");

        sleep(1);

        locker.Unlock();

    }

 

    locker2.Unlock();

 

    return((void *)0);

}

 

 

int main(void)

{

    int err;

    pthread_t tid1, tid2;

    void* tret;

 

    int count = 10;

 

    printf("PID=%d\n", getpid());

    // thread 1

    err = pthread_create(&tid1, NULL, thr_fn, NULL);

    if (err != 0)

    {

        printf("can't create thread : %s\n", strerror(err));

    }

    printf("Create thread 1 : %u \n", (unsigned int)tid1);

 

    // thread 2

    err = pthread_create(&tid2, NULL, thr_fn2, &count);

    if (err != 0)

    {

        printf("can't create thread : %s\n", strerror(err));

    }

    printf("Create thread 2 : %u \n", (unsigned int)tid2);

 

    printids("main thread:");

    sleep(1);

 

    // pthread_cancel(tid1);

    // printf("Cancel thread 1\n");

 

    err = pthread_join(tid1, &tret);

    if (err != 0)

        printf("can't join with thread 1: %s\n", strerror(err));

 

    printf("thread 1 exit code %d\n", (int)tret);

 

    // thread 2

    /* err = pthread_create(&tid2, NULL, thr_fn, &count);

    if (err != 0)

    {

        printf("can't create thread : %s\n", strerror(err));

    }

    printf("Create thread 2 : %u \n", (unsigned int)tid2);      */

 

    ////////////////////////////////

    err = pthread_join(tid2, &tret);

    if (err != 0)

        printf("can't join with thread 2: %s\n", strerror(err));

 

    printf("thread 2 exit code %d\n", (int)tret);

 

    return 0;

}

 

 

Shell 1:

g++ -g -o test deadlock.cc lpthread

nochen@bclnx64 ~/test$ ./test

PID=6283

Create thread 1 : 1084229984

Create thread 2 : 1094719840

main thread: pid 6283 tid 2505602208 (0x955874a0)

Func 1 Time 0 : new thread:  pid 6283 tid 1084229984 (0x40a00960)

 

Shell 2:

gdb ./test

(gdb) attach 6283

(gdb) info thread

  3 Thread 1084229984 (LWP 6284)  0x0000003cf620adfb in __lll_mutex_lock_wait () from /lib64/tls/libpthread.so.0

  2 Thread 1094719840 (LWP 6285)  0x0000003cf620adfb in __lll_mutex_lock_wait () from /lib64/tls/libpthread.so.0

* 1 Thread 182894228640 (LWP 6283)  0x0000003cf6206ffb in pthread_join () from /lib64/tls/libpthread.so.0

(gdb) thread 2

[Switching to thread 2 (Thread 1094719840 (LWP 6285))]#0  0x0000003cf620adfb in __lll_mutex_lock_wait ()

   from /lib64/tls/libpthread.so.0

(gdb) info register

rax            0xfffffffffffffffc       -4

rbx            0x0      0

rcx            0xffffffffffffffff       -1

rdx            0x2      2

rsi            0x0      0

rdi            0x5016a0 5248672

rbp            0x414011b0       0x414011b0

rsp            0x41401100       0x41401100

rip            0x3cf620adfb     0x3cf620adfb <__lll_mutex_lock_wait+27>

eflags         0x202    514

 (gdb) x/32gx 0x414011b0 - 16

0x414011a0:     0x0000000000000000      0x00000000005016a0

0x414011b0:     0x00000000414011d0      0x0000000000400bc5

0x414011c0:     0x0000000a00000000      0x0000007fbffff3cc

0x414011d0:     0x0000000000000000      0x0000003cf620610a

0x414011e0:     0x0000000000000000      0x0000000041401960

0x414011f0:     0x0000000041401960      0x0000000000000000

(gdb) x/32i 0x0000000000400bc5 - 2

0x400bc3 <_Z7thr_fn2Pv+93>:     add    %al,(%rax)

0x400bc5 <_Z7thr_fn2Pv+95>:     mov    $0x400fd7,%edi

0x400bca <_Z7thr_fn2Pv+100>:    callq  0x400a88 <_Z8printidsPKc>

0x400bcf <_Z7thr_fn2Pv+105>:    mov    $0x1,%edi

0x400bd4 <_Z7thr_fn2Pv+110>:    callq  0x400938

0x400bd9 <_Z7thr_fn2Pv+115>:    mov    $0x5016a0,%edi

0x400bde <_Z7thr_fn2Pv+120>:    callq  0x400e20 <_ZN5Mutex6UnlockEv>

0x400be3 <_Z7thr_fn2Pv+125>:    lea    0xfffffffffffffff0(%rbp),%rax

0x400be7 <_Z7thr_fn2Pv+129>:    incl   (%rax)

0x400be9 <_Z7thr_fn2Pv+131>:    jmp    0x400ba1 <_Z7thr_fn2Pv+59>

0x400beb <_Z7thr_fn2Pv+133>:    mov    $0x5016e0,%edi

0x400bf0 <_Z7thr_fn2Pv+138>:    callq  0x400e20 <_ZN5Mutex6UnlockEv>

0x400bf5 <_Z7thr_fn2Pv+143>:    mov    $0x0,%eax

0x400bfa <_Z7thr_fn2Pv+148>:    leaveq

0x400bfb <_Z7thr_fn2Pv+149>:    retq

(gdb) thread 3

[Switching to thread 3 (Thread 1084229984 (LWP 6284))]#0  0x0000003cf620adfb in __lll_mutex_lock_wait ()

   from /lib64/tls/libpthread.so.0

(gdb) info register

rax            0xfffffffffffffffc       -4

rbx            0x0      0

rcx            0xffffffffffffffff       -1

rdx            0x2      2

rsi            0x0      0

rdi            0x5016e0 5248736

rbp            0x40a001b0       0x40a001b0

rsp            0x40a00100       0x40a00100

rip            0x3cf620adfb     0x3cf620adfb <__lll_mutex_lock_wait+27>

eflags         0x202    514

(gdb) x/16gx 0x40a001b0 - 16

0x40a001a0:     0x0000000040a001d0      0x00000000005016e0

0x40a001b0:     0x0000000040a001d0      0x0000000000400b2f

0x40a001c0:     0x000003e800000001      0x0000000000000000

0x40a001d0:     0x0000000000000000      0x0000003cf620610a

0x40a001e0:     0x0000000000000000      0x0000000040a00960

0x40a001f0:     0x0000000040a00960      0x0000000000000000

0x40a00200:     0x0000003cf6206080      0x0000003cf620d4e0

0x40a00210:     0x0000000000000000      0x0000003cf620d4e0

(gdb) x/32i 0x0000000000400b2f-2

0x400b2d <_Z6thr_fnPv+93>:      add    %al,(%rax)

0x400b2f <_Z6thr_fnPv+95>:      mov    $0x400fd7,%edi

0x400b34 <_Z6thr_fnPv+100>:     callq  0x400a88 <_Z8printidsPKc>

0x400b39 <_Z6thr_fnPv+105>:     mov    $0x1,%edi

0x400b3e <_Z6thr_fnPv+110>:     callq  0x400938

0x400b43 <_Z6thr_fnPv+115>:     mov    $0x5016e0,%edi

0x400b48 <_Z6thr_fnPv+120>:     callq  0x400e20 <_ZN5Mutex6UnlockEv>

0x400b4d <_Z6thr_fnPv+125>:     lea    0xfffffffffffffff0(%rbp),%rax

0x400b51 <_Z6thr_fnPv+129>:     incl   (%rax)

0x400b53 <_Z6thr_fnPv+131>:     jmp    0x400b0b <_Z6thr_fnPv+59>

0x400b55 <_Z6thr_fnPv+133>:     mov    $0x5016a0,%edi

0x400b5a <_Z6thr_fnPv+138>:     callq  0x400e20 <_ZN5Mutex6UnlockEv>

0x400b5f <_Z6thr_fnPv+143>:     mov    $0x0,%eax

0x400b64 <_Z6thr_fnPv+148>:     leaveq

0x400b65 <_Z6thr_fnPv+149>:     retq

0x400b66 <_Z7thr_fn2Pv>:        push   %rbp

0x400b67 <_Z7thr_fn2Pv+1>:      mov    %rsp,%rbp

0x400b6a <_Z7thr_fn2Pv+4>:      sub    $0x10,%rsp

0x400b6e <_Z7thr_fn2Pv+8>:      mov    %rdi,0xfffffffffffffff8(%rbp)

0x400b72 <_Z7thr_fn2Pv+12>:     movl   $0x3e8,0xfffffffffffffff4(%rbp)

0x400b79 <_Z7thr_fn2Pv+19>:     cmpq   $0x0,0xfffffffffffffff8(%rbp)

0x400b7e <_Z7thr_fn2Pv+24>:     je     0x400b89 <_Z7thr_fn2Pv+35>

0x400b80 <_Z7thr_fn2Pv+26>:     mov    0xfffffffffffffff8(%rbp),%rax

0x400b84 <_Z7thr_fn2Pv+30>:     mov    (%rax),%eax

0x400b86 <_Z7thr_fn2Pv+32>:     mov    %eax,0xfffffffffffffff4(%rbp)

0x400b89 <_Z7thr_fn2Pv+35>:     mov    $0x5016e0,%edi

0x400b8e <_Z7thr_fn2Pv+40>:     callq  0x400e38 <_ZN5Mutex4LockEv>

0x400b93 <_Z7thr_fn2Pv+45>:     movl   $0x0,0xfffffffffffffff0(%rbp)

0x400b9a <_Z7thr_fn2Pv+52>:     movl   $0x0,0xfffffffffffffff0(%rbp)

0x400ba1 <_Z7thr_fn2Pv+59>:     mov    0xfffffffffffffff0(%rbp),%eax

0x400ba4 <_Z7thr_fn2Pv+62>:     cmp    0xfffffffffffffff4(%rbp),%eax

0x400ba7 <_Z7thr_fn2Pv+65>:     jge    0x400beb <_Z7thr_fn2Pv+133>

(gdb) Quit

 Thus we know function thr_fn and thr_fn2 is dead-lock!

阅读(7102) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~