RT-Thread Getting Started Study Notes-Keil MDK software debugging and troubleshooting assert

background

  • Software debugging, not much code is written, without debugging, you can know where the problem is, especially the RT_ASSERT assertion.
  • There are more functions. After the RT_ASSERT assertion appears, it is difficult to immediately understand what went wrong, such as the rt_free assertion. Where did the call to rt_free cause it?
  • How to use Keil MDK5 Debug to quickly assert the true position of the assertion and debug the software?

case study

  • I wrote a BUG program before to test the use of RT-Thread mailbox, and must now assert: rt_free, because the application and release of dynamic memory are used.
  • First of all, we need to locate the problem. We can't say that there is a problem with the rt-thread rt_free function! ! It should be caused by incorrect use.

2021-02-19_180711.png

2021-02-20_104007.png

2021-02-20_104124.png

  • Keil MDK5 is in Debug mode, you can find the calling relationship of functions, such as the caller, in the debugging window [Call Stack], call stack window.

2021-02-20_104330.png

2021-02-20_105218.png

2021-02-20_105346.png

2021-02-20_105450.png

2021-02-20_105546.png

2021-02-20_105744.png

  • Through [follow the vine], find the real calling function: the location of the problem! !

2021-02-20_105847.png

 

Troubleshooting

  • The problem with this routine is caused by the rt_free null pointer, so it must be caused by the improper pair operation of applying and releasing memory.
  • Because I didn’t find the problem at once, I set a breakpoint at the problem code location and found that there was a problem with the rt_free pointer during the second execution, or a wild pointer
  • Quote: extern void list_mem(void); Add to print and find that the memory is getting more and more! ! (A lot of rt_free releases!!)
  • The part of the code that went wrong is as follows:
struct mb_msg
{
    rt_uint8_t *data_ptr;
    rt_uint32_t data_size;
};


static void thread1_entry(void *param)
{
    struct mb_msg *msg_recv_ptr1;
    struct mb_msg *msg_send_ptr1;
    char sbuf[6] = {'T', 'a', 's', 'k', '1', '.'};
    msg_send_ptr1 = (struct mb_msg *)rt_malloc(sizeof(struct mb_msg)); /* !!!! 申请内存的位置放错了!!!*/

    while(1)
    {
        if (rt_mb_recv(&t1_mb, (rt_ubase_t *)&msg_recv_ptr1, RT_WAITING_FOREVER) == RT_EOK)
        {
            rt_kprintf("thread 1:[recv=%s], print 1.\n", msg_recv_ptr1->data_ptr);
            rt_thread_mdelay(10);
            rt_free(msg_recv_ptr1->data_ptr);
            rt_free(msg_recv_ptr1);
            rt_thread_mdelay(500);
            msg_send_ptr1->data_size = sizeof(sbuf);
            msg_send_ptr1->data_ptr = (rt_uint8_t *)rt_malloc(msg_send_ptr1->data_size);
            rt_memcpy(msg_send_ptr1->data_ptr, sbuf, sizeof(sbuf));
            rt_kprintf("thread 1:[send=%s]\n", msg_send_ptr1->data_ptr);
            rt_mb_send(&t2_mb, (rt_uint32_t)msg_send_ptr1);
        }
    }
}
  • It turned out that a place where the memory was applied for was misplaced, causing this function to only apply for memory once during initialization. When used, it is a wild pointer.
  • Solution: Put the piece of code that applies for memory in the while(1) loop, and apply for memory for each operation! !
static void thread1_entry(void *param)
{
    struct mb_msg *msg_recv_ptr1;
    struct mb_msg *msg_send_ptr1;
    char sbuf[6] = {'T', 'a', 's', 'k', '1', '.'};

    while(1)
    {
        if (rt_mb_recv(&t1_mb, (rt_ubase_t *)&msg_recv_ptr1, RT_WAITING_FOREVER) == RT_EOK)
        {
            rt_kprintf("thread 1:[recv=%s], print 1.\n", msg_recv_ptr1->data_ptr);
            rt_thread_mdelay(10);
            rt_free(msg_recv_ptr1->data_ptr);
            list_mem();
            rt_free(msg_recv_ptr1);
            list_mem();
            rt_thread_mdelay(500);
            msg_send_ptr1 = (struct mb_msg *)rt_malloc(sizeof(struct mb_msg));
            msg_send_ptr1->data_size = sizeof(sbuf);
            msg_send_ptr1->data_ptr = (rt_uint8_t *)rt_malloc(msg_send_ptr1->data_size);
            rt_memcpy(msg_send_ptr1->data_ptr, sbuf, sizeof(sbuf));
            rt_kprintf("thread 1:[send=%s]\n", msg_send_ptr1->data_ptr);
            rt_mb_send(&t2_mb, (rt_uint32_t)msg_send_ptr1);
        }
    }
}

to sum up

  • RT_ASSERT is still relatively easy to use, pay attention to the correct breakpoints, debugging, very efficient.
  • Summarize more debugging methods to solve actual problems.

Guess you like

Origin blog.csdn.net/tcjy1000/article/details/113915080