Categories
Uncategorized

Using gdb debugging c ++ program

 

Part (using c ++ cross-platform program) Speaking of, I’m not afraid of making things, I’m afraid of is made out of things, if things go wrong, I do not know why. So debugging analysis is an important tool.

C ++ debugger is a complex of living. Although most IDE debugging during development can be solved, but inevitable, there are many things you need to restore it in a production environment. Analyze it, and then solve it is a mature .gdb tools around it has a lot of tools to choose from. but gdb at the command line mode or simply so many tools.

Ado, and now I use gdb debugger to analyze it.

 

Generate a dump file:

Enter the command in a shell:

ulimit -c unlimited;

Then run your program, if the program crashes at this time, it will generate a directory in a file named core. (This also look at the system configuration.)

Use the command gdb Test1 core load files. Or it’s detailed command gdb -c core -e Test1 –symbols Test1 –readnow

 

Below is a screenshot of a command output:

The above figure can be explained much because we now just want to get started. We can only note that three red box in the figure above.

Red box 1: command line which app7 is an executable file, which is a core dump file.

Red frame 2: gdb indicated found its corresponding symbol in the app7.

Red box 3: identify core file is generated via app7 here is to prevent loading the wrong executable file.

 

Note the following points:

If you are using sanitize, please cancel. Otherwise, no dump file when a crash. Instead, an error report.

When an executable file, you should use debug mode, you can also use RelWithDebInfo mode. The main purpose of the program is the ability to get debugging symbols.

If there is no symbol information, it can also debug, but the process will be difficult on many times, after all, we are debugging, not crack, but also not to mention, gdb debugging with the crack but it is still somewhat interlinked.

Because there are so many gdb debugging commands from the timeliness, the need to remember all the instructions only need to know the common commands like. Even if it was protracted and painstaking remember all the instructions, over time, if not, then also forget a. they are able to see documents in English, I feel more useful than remember command.

Most errors during development IDE has been solved. The error occurred when the situation requires debugging core dump files are generally run, I briefly outline the following categories

Pointer is NULL. Stack overflow, divide by zero, deadlock.

Debugging pointer is NULL

A program given below, contents of the program are as follows:

#include 
void bar(int* p)
{
    int aa=*p;
}
void foo()
{
    int* p=NULL;
    bar(p);
}
int main(int argc, const char * argv[])
{
    foo();
    return 0;
}

  

Compiled assuming that the output is app0, after running app0 now I have core file to load the core file screenshot follows:

After loading is completed, you can see gdb have pointed to the app0.cpp to 15 lines in question.

Then we go back to the source code, see line 15, is indeed a problem. All null problem has been resolved. Is not very simple? Oh, but we want to go one. Why look in the end.

1. I using p p, (p is a first Print, gdb instruction is, the second parameter is the p p);

This shows that p is a 0. So go wrong here.

2. It stands to reason, the above analysis can draw conclusions. But here I would like further.

First, I listed all the threads

info thread

 

 

 

Only one thread, very good.

Secondly, I look at the stack

bt

 

 

You can see the call stack, it is so parameter p is generated from the function foo foo bar in the function call.

As can be seen, although the null reference is resolved, back to think about it, here a little hindsight meaning. Some people may ask, “are you already know in advance that a null reference then to analyze, which is … who will not” true reality null reference which does analysis of them little more difficult than this, but this series is so that people will use basic gdb. know each type generally look like. when in reality, the analysis of the good and directions problem among specific work . only when reanalysis.

 

Debug stack overflow

General recursive function exits stack overflow condition is not fulfilled, leading to the cycle call. Debugging stack overflow is relatively simple, feature is also very obvious.

Let me borrow an example to explain the author of this example is a foreigner, who it is. I forgot.

 

#include 
#include 
#include 
#include 
#include 
void procF(int i)
{
    int buffer[128] = {-1, 0, i+1, 0, -1};
    procF(buffer[2]);
}
void procE()
{
    procF(1);
}
#define THREAD_DECLARE(num,func) void bar_##num()\
{\
sleep(3);\
func;\
}\
\
void foo_##num()\
{\
bar_##num();\
}\
\
void * thread_##num (void *arg)\
{\
foo_##num();\
\
return 0;\
}
THREAD_DECLARE(one,procE())
THREAD_DECLARE(two,sleep(-1))
THREAD_DECLARE(three,sleep(-1))
THREAD_DECLARE(four,sleep(-1))
THREAD_DECLARE(five,sleep(-1))
#define THREAD_CREATE(num) {pthread_t threadID_##num; pthread_create (&threadID_##num, NULL,thread_##num, NULL);}
int main(int argc, const char * argv[])
{
    THREAD_CREATE(one)
    THREAD_CREATE(two)
    THREAD_CREATE(three)
    THREAD_CREATE(four)
    THREAD_CREATE(five)
    sleep(-1);
    return 0;
}

 

  

 

The above documents is very simple, a macro is defined, then use this macro, copy the generated 5 threads which thread_one this thread, it will fall into an infinite loop. It called in a loop in procF, resulting in a stack overflow.

Let’s look at what it looks like. I specifically how to load the core here a little before. Gdb content directly to see it.

It says can not access memory at address xxx, then list the specific location is the most recently executed a brace, there is no reference value

1. I look at all the threads

6 threads, remove the first one is not able to read the memory of that error, the rest are in sleep. Here follow the prompts to gdb (procF it says there is a problem), I look at the thread 1, because it only stays in the procF;

2. Instruction thread 1 represents a switch to thread stack 1 and then view it and see how to get to the procF of.

Here found procF calls itself, according to experience, there should be a stack overflow. But in order to confirm this, I decided to see how many layers it calls.

3. The call stack is a print instruction bt .bt -20 print a bottom 20 calls

It found that 15,000 calls .. Another advantage is that here you can see the source. ProcE come from.

Next you can go to view the contents of the proceE in gdb is also can be done, as shown below

Well, this call stack overflow is solved.

 

However, it still may start here. We know that the called function is placed in the thread of the space, and we look at from the space, there is no law.

In order to display the stack space, the need to use a command gdb x (View)

Detailed observations bt -20 returned, similar to the following can be seen

 

#14971 0x00005636f87b2c91 in procF (i=1) at /root/clionproject/Test1/dump/app6.cpp:16

#14972 0x00005636f87b2cb6 in procE () at /root/clionproject/Test1/dump/app6.cpp:20

Where # 14971 is the frame number.

Behind 0x00005636f87b2c91, the position of the code in memory, i.e. app6.cpp:. 16 line corresponding to this binary code in the memory location

gdb huh

 

P $ rsp and info r $ rsp print the representative value of the register inside rsp. $ rsp register pointing to the top of the stack, so its value must be the top of the stack.

I’ll check the stack.

This is mainly drawn x .x instruction is an instruction to view the specified address.

 

Division by zero

Division by zero is a simple question. I am not on the code.

Loading core file will be displayed

He says this is an arithmetic problem. Occurred in procD function

Now I check what is procD

Disass disassembly is meant, the instruction corresponding to the address is printed disassembly.

Figure above red box, which is now running position instruction system that the error in this position. It is clearly to see a division idivl. Likelihood here is a divide by zero.

See assembly instructions idivl -0x8 (% rbp), which -x8 (% rbp), representing a value, this value is the divisor. So I want to find the value it represents.

First look rbp what stuff, rbp is a register that points to a base point, you can simply think of all internal functions of the application stack variables (such as int a = 0, etc.), it is converted by rbp.

Second, look at this address is valid and -8.

Since $ rbp-0x8 is the address of a variable, then we will see what the value of this address is written.

I can see that it is indeed written 0.

 

Divisor is zero, is over.

 

 

Deadlock

Deadlock is a common problem, but the deadlock has a characteristic, not every deadlock will be dump down. So when it came to a deadlock, and sometimes need to use the online debugging approach, but this approach.

Now I use the following code

#include 
#include 
#include 
#include 
#include 

static int sequence1 = 0;
static int sequence2 = 0;

std::mutex lock1;
std::mutex lock2;

int func1()
{
    lock1.lock();
    sleep(1);
    sequence1++;
    lock2.lock();
    sequence2++;
    lock1.unlock();
    lock2.unlock();
    return sequence1;
}

int func2()
{
    lock2.lock();
    sleep(1);
    sequence2++;
    lock1.lock();
    sequence1++;
    lock2.unlock();
    lock1.unlock();
    return sequence1;
}


void* thread1(void *arg)
{
    int rev = 0;
    while(1)
    {
        rev = func1();

        if (rev == 100000)
        {
            pthread_exit(NULL);
        }
    }
}

void* thread2(void *arg)
{
    int rev = 0;
    while(1)
    {
        rev = func2();

        if (rev == 100000)
        {
            pthread_exit(NULL);
        }
    }
}

void* thread3(void *arg)
{
    int count = 0;
    while(1)
    {
        sleep(1);
        if ( count++ > 10000)
        {
            pthread_exit(NULL);
        }
    }
}

void* thread4(void *arg)
{
    int count = 0;
    while(1)
    {
        sleep(1);
        if ( count++ > 10000)
        {
            pthread_exit(NULL);
        }
    }
}



int main()
{
    pthread_t tid[4];
    if(pthread_create(&tid[0], NULL, & thread1, NULL) != 0)
    {
        _exit(1);
    }
    if(pthread_create(&tid[1], NULL, & thread2, NULL) != 0)
    {
        _exit(1);
    }

    if(pthread_create(&tid[2], NULL, & thread3, NULL) != 0)
    {
        _exit(1);
    }

    if(pthread_create(&tid[3], NULL, & thread4, NULL) != 0)
    {
        _exit(1);
    }
    sleep(5);
    pthread_join(tid[0], NULL);
    pthread_join(tid[1], NULL);
    pthread_join(tid[2], NULL);
    pthread_join(tid[3], NULL);
    return 0;
}

 

 

  

The code above mainly in func1 and func2, they may have to wait for another deadlock. Now I run the following to compile it.

Because it’s just a deadlock, all did not dump on my machine down, I use gdb, online debug it. Screenshot below

Ps I first found the process id is 14661, with gdb attached to it, now start debugging.

Look at the thread

There are two threads may deadlock. Take a look at how the thread 2 calls. Call stack huh.

It is called func1, I look at the contents of func1

It prompts two variables are lock1 and lock2. So I wanted to see these two variables

Suggesting that the two locks are held by different threads.

And then look at the call stack thread 2

We can see, it prompts thread 14662 stopped at lock2.lock () method, where you want to get ownership of the thread lock while lock2, according to a screenshot has been held by the 14663.

Lock1 you can also get the details of the same way. I will not repeat here.

 

So this deadlock was I found out why.

 

summary

Problems encountered in the real reality, it will not be found like this quickly, because this is creating a problem and then to solve, meaning a little hindsight, such as reality deadlock, find the corresponding lock variable This step is not would be so easy, it requires patience and luck, but the first step is to first use gdb familiar with the general problems when the call stack mode, and then try to go the direction of possible errors, and then solve it. If you just remember the cold gdb commands in my eyes just as more than just remember a few English words, I think of little significance.

 

Leave a Reply