mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-11-04 09:01:40 +01:00 
			
		
		
		
	1. This is just a temporary solution, it will be removed when umm_malloc is ready 2. Support memory canaries mechanism 2. Add debug code to show allocated memory info
		
			
				
	
	
		
			194 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			194 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include "heap_regions_debug.h"
 | 
						|
#include "FreeRTOS.h"
 | 
						|
#include "task.h"
 | 
						|
#include <stdlib.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
#if (configENABLE_MEMORY_DEBUG == 1)
 | 
						|
 | 
						|
static os_block_t g_malloc_list, *g_free_list=NULL, *g_end;
 | 
						|
static size_t g_heap_struct_size;
 | 
						|
static mem_dbg_ctl_t g_mem_dbg;
 | 
						|
char g_mem_print = 0;
 | 
						|
static portMUX_TYPE *g_malloc_mutex = NULL;
 | 
						|
static unsigned int g_alloc_bit;
 | 
						|
#define MEM_DEBUG(...)
 | 
						|
 | 
						|
void mem_debug_init(size_t size, void *start, void *end, portMUX_TYPE *mutex, unsigned int alloc_bit)
 | 
						|
{
 | 
						|
    MEM_DEBUG("size=%d start=%p end=%p mutex=%p alloc_bit=0x%x\n", size, start, end, mutex, alloc_bit);
 | 
						|
    memset(&g_mem_dbg, 0, sizeof(g_mem_dbg));
 | 
						|
    memset(&g_malloc_list, 0, sizeof(g_malloc_list));
 | 
						|
    g_malloc_mutex = mutex;
 | 
						|
    g_heap_struct_size = size;
 | 
						|
    g_free_list = start;
 | 
						|
    g_end = end;
 | 
						|
    g_alloc_bit = alloc_bit;
 | 
						|
}
 | 
						|
 | 
						|
void mem_debug_push(char type, void *addr)
 | 
						|
{
 | 
						|
    os_block_t *b = (os_block_t*)addr;
 | 
						|
    debug_block_t *debug_b = DEBUG_BLOCK(b);
 | 
						|
 | 
						|
    MEM_DEBUG("push type=%d addr=%p\n", type, addr);
 | 
						|
    if (g_mem_print){
 | 
						|
        if (type == DEBUG_TYPE_MALLOC){
 | 
						|
            ets_printf("task=%s t=%s s=%u a=%p\n", debug_b->head.task?debug_b->head.task:"", type==DEBUG_TYPE_MALLOC?"m":"f", b->size&(~g_alloc_bit), addr);
 | 
						|
        } else {
 | 
						|
            ets_printf("task=%s t=%s s=%u a=%p\n", debug_b->head.task?debug_b->head.task:"", type==DEBUG_TYPE_MALLOC?"m":"f", b->size&(~g_alloc_bit), addr);
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        mem_dbg_info_t *info = &g_mem_dbg.info[g_mem_dbg.cnt%DEBUG_MAX_INFO_NUM];
 | 
						|
 | 
						|
        info->addr = addr;
 | 
						|
        info->type = type;
 | 
						|
        info->time = g_mem_dbg.cnt;
 | 
						|
        g_mem_dbg.cnt++;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void mem_debug_malloc_show(void)
 | 
						|
{
 | 
						|
    os_block_t *b = g_malloc_list.next;
 | 
						|
    debug_block_t *d;
 | 
						|
 | 
						|
    taskENTER_CRITICAL(g_malloc_mutex);
 | 
						|
    while (b){
 | 
						|
        d = DEBUG_BLOCK(b);
 | 
						|
        d->head.task[3] = '\0';
 | 
						|
        ets_printf("t=%s s=%u a=%p\n", d->head.task?d->head.task:"", b->size&(~g_alloc_bit), b);
 | 
						|
        b = b->next;
 | 
						|
    }
 | 
						|
    taskEXIT_CRITICAL(g_malloc_mutex);
 | 
						|
}
 | 
						|
 | 
						|
void mem_debug_show(void)
 | 
						|
{
 | 
						|
    uint32_t i;
 | 
						|
 | 
						|
    if (!g_mem_print) return;
 | 
						|
 | 
						|
    for (i=0; i<DEBUG_MAX_INFO_NUM; i++){
 | 
						|
        ets_printf("%u %s %p\n", g_mem_dbg.info[i].time, g_mem_dbg.info[i].type == DEBUG_TYPE_FREE?"f":"m", g_mem_dbg.info[i].addr);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void mem_check_block(void* data)
 | 
						|
{
 | 
						|
    debug_block_t *b = DEBUG_BLOCK(data);
 | 
						|
 | 
						|
    MEM_DEBUG("check block data=%p\n", data);
 | 
						|
    if (data && (HEAD_DOG(b) == DEBUG_DOG_VALUE)){
 | 
						|
        if (TAIL_DOG(b) != DEBUG_DOG_VALUE){
 | 
						|
            ets_printf("f task=%s a=%p h=%08x t=%08x\n", b->head.task?b->head.task:"", b, HEAD_DOG(b), TAIL_DOG(b));
 | 
						|
            DOG_ASSERT();
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        ets_printf("f task=%s a=%p h=%08x\n", b->head.task?b->head.task:"", b, HEAD_DOG(b));\
 | 
						|
        DOG_ASSERT();
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void mem_init_dog(void *data)
 | 
						|
{
 | 
						|
    debug_block_t *b = DEBUG_BLOCK(data);
 | 
						|
    xTaskHandle task;
 | 
						|
 | 
						|
    MEM_DEBUG("init dog, data=%p debug_block=%p block_size=%x\n", data, b, b->os_block.size);
 | 
						|
    if (!data) return;
 | 
						|
#if (INCLUDE_pcTaskGetTaskName == 1)
 | 
						|
    task = xTaskGetCurrentTaskHandle();
 | 
						|
    if (task){
 | 
						|
        strncpy(b->head.task, pcTaskGetTaskName(task), 3);
 | 
						|
        b->head.task[3] = '\0';
 | 
						|
    } 
 | 
						|
#else
 | 
						|
    b->head.task = '\0';
 | 
						|
#endif
 | 
						|
    HEAD_DOG(b) = DEBUG_DOG_VALUE;
 | 
						|
    TAIL_DOG(b) = DEBUG_DOG_VALUE;
 | 
						|
}
 | 
						|
 | 
						|
void mem_check_all(void* pv)
 | 
						|
{
 | 
						|
    os_block_t *b;
 | 
						|
 | 
						|
    if (pv){
 | 
						|
        char *puc = (char*)(pv);
 | 
						|
        os_block_t *b;
 | 
						|
        puc -= (g_heap_struct_size - BLOCK_TAIL_LEN - BLOCK_HEAD_LEN);
 | 
						|
        b = (os_block_t*)puc;
 | 
						|
        mem_check_block(b);
 | 
						|
    }
 | 
						|
 | 
						|
    taskENTER_CRITICAL(g_malloc_mutex);
 | 
						|
    b = g_free_list->next;
 | 
						|
    while(b && b != g_end){
 | 
						|
        mem_check_block(b);
 | 
						|
        ets_printf("check b=%p size=%d ok\n", b, b->size);
 | 
						|
        b = b->next;
 | 
						|
    }
 | 
						|
    taskEXIT_CRITICAL(g_malloc_mutex);
 | 
						|
}
 | 
						|
 | 
						|
void mem_malloc_show(void)
 | 
						|
{
 | 
						|
    os_block_t *b = g_malloc_list.next;
 | 
						|
    debug_block_t *debug_b;
 | 
						|
 | 
						|
    while (b){
 | 
						|
        debug_b = DEBUG_BLOCK(b);
 | 
						|
        ets_printf("%s %p %p %u\n", debug_b->head.task, debug_b, b, b->size&(~g_alloc_bit));
 | 
						|
        b = b->next;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void mem_malloc_block(void *data)
 | 
						|
{
 | 
						|
    os_block_t *b = (os_block_t*)data;
 | 
						|
 | 
						|
    MEM_DEBUG("mem malloc block data=%p, size=%u\n", data, b->size&(~g_alloc_bit));
 | 
						|
    mem_debug_push(DEBUG_TYPE_MALLOC, data);
 | 
						|
 | 
						|
    if (b){
 | 
						|
        b->next = g_malloc_list.next;
 | 
						|
        g_malloc_list.next = b;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void mem_free_block(void *data)
 | 
						|
{
 | 
						|
    os_block_t *del = (os_block_t*)data;
 | 
						|
    os_block_t *b = g_malloc_list.next;
 | 
						|
    os_block_t *pre = &g_malloc_list;
 | 
						|
    debug_block_t *debug_b;
 | 
						|
 | 
						|
    MEM_DEBUG("mem free block data=%p, size=%d\n", data, del->size&(~g_alloc_bit));
 | 
						|
    mem_debug_push(DEBUG_TYPE_FREE, data);
 | 
						|
 | 
						|
    if (!del) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    while (b){
 | 
						|
        if ( (del == b) ){
 | 
						|
            pre->next = b->next;
 | 
						|
            b->next = NULL;
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        pre = b;
 | 
						|
        b = b->next;
 | 
						|
    }
 | 
						|
 | 
						|
    debug_b = DEBUG_BLOCK(del);
 | 
						|
    ets_printf("%s %p %p %u already free\n", debug_b->head.task, debug_b, del, del->size&(~g_alloc_bit));
 | 
						|
    mem_malloc_show();
 | 
						|
    abort();
 | 
						|
}
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
 |