diff --git a/src/Kconfig b/src/Kconfig index f5efdf7b35..d8ddbfc838 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -161,6 +161,22 @@ menu "Memory Management" endif endchoice + if RT_USING_SMALL_MEM + config RT_USING_MEMTRACE + bool "Enable memory trace" + default n + help + When enable RT_USING_MEMTRACE with shell, developer can call cmd: + 1. memtrace + to dump memory block information. + 2. memcheck + to check memory block to avoid memory overwritten. + + And developer also can call memcheck() in each of scheduling + to check memory block to find which thread has wrongly modified + memory. + endif + config RT_USING_HEAP bool default n if RT_USING_NOHEAP diff --git a/src/mem.c b/src/mem.c index 92c85385ab..a0c60a8670 100644 --- a/src/mem.c +++ b/src/mem.c @@ -113,6 +113,10 @@ struct heap_mem rt_uint16_t used; rt_size_t next, prev; + +#ifdef RT_USING_MEMTRACE + rt_uint8_t thread[4]; /* thread name */ +#endif }; /** pointer to the heap: for alignment, heap_ptr is now a pointer instead of an array */ @@ -133,6 +137,22 @@ static rt_size_t mem_size_aligned; #ifdef RT_MEM_STATS static rt_size_t used_mem, max_mem; #endif +#ifdef RT_USING_MEMTRACE +rt_inline void rt_mem_setname(struct heap_mem *mem, const char *name) +{ + int index; + for (index = 0; index < sizeof(mem->thread); index ++) + { + if (name[index] == '\0') break; + mem->thread[index] = name[index]; + } + + for (; index < sizeof(mem->thread); index ++) + { + mem->thread[index] = ' '; + } +} +#endif static void plug_holes(struct heap_mem *mem) { @@ -217,6 +237,9 @@ void rt_system_heap_init(void *begin_addr, void *end_addr) mem->next = mem_size_aligned + SIZEOF_STRUCT_MEM; mem->prev = 0; mem->used = 0; + #ifdef RT_USING_MEMTRACE + rt_mem_setname(mem, "INIT"); + #endif /* initialize the end of the heap */ heap_end = (struct heap_mem *)&heap_ptr[mem->next]; @@ -224,6 +247,9 @@ void rt_system_heap_init(void *begin_addr, void *end_addr) heap_end->used = 1; heap_end->next = mem_size_aligned + SIZEOF_STRUCT_MEM; heap_end->prev = mem_size_aligned + SIZEOF_STRUCT_MEM; + #ifdef RT_USING_MEMTRACE + rt_mem_setname(heap_end, "INIT"); + #endif rt_sem_init(&heap_sem, "heap", 1, RT_IPC_FLAG_FIFO); @@ -309,6 +335,9 @@ void *rt_malloc(rt_size_t size) mem2->used = 0; mem2->next = mem->next; mem2->prev = ptr; + #ifdef RT_USING_MEMTRACE + rt_mem_setname(mem2, " "); + #endif /* and insert it between mem and mem->next */ mem->next = ptr2; @@ -342,6 +371,12 @@ void *rt_malloc(rt_size_t size) } /* set memory block magic */ mem->magic = HEAP_MAGIC; + #ifdef RT_USING_MEMTRACE + if (rt_thread_self()) + rt_mem_setname(mem, rt_thread_self()->name); + else + rt_mem_setname(mem, "NONE"); + #endif if (mem == lfree) { @@ -447,6 +482,9 @@ void *rt_realloc(void *rmem, rt_size_t newsize) mem2->used = 0; mem2->next = mem->next; mem2->prev = ptr; +#ifdef RT_USING_MEMTRACE + rt_mem_setname(mem2, " "); +#endif mem->next = ptr2; if (mem2->next != mem_size_aligned + SIZEOF_STRUCT_MEM) { @@ -543,11 +581,19 @@ void rt_free(void *rmem) rt_sem_take(&heap_sem, RT_WAITING_FOREVER); /* ... which has to be in a used state ... */ + if (!mem->used || mem->magic != HEAP_MAGIC) + { + rt_kprintf("to free a bad data block:\n"); + rt_kprintf("mem: 0x%08x, used flag: %d, magic code: 0x%04x\n", mem, mem->used, mem->magic); + } RT_ASSERT(mem->used); RT_ASSERT(mem->magic == HEAP_MAGIC); /* ... and is now unused. */ mem->used = 0; mem->magic = HEAP_MAGIC; +#ifdef RT_USING_MEMTRACE + rt_mem_setname(mem, " "); +#endif if (mem < lfree) { @@ -588,7 +634,77 @@ void list_mem(void) rt_kprintf("maximum allocated memory: %d\n", max_mem); } FINSH_FUNCTION_EXPORT(list_mem, list memory usage information) -#endif + +#ifdef RT_USING_MEMTRACE +int memcheck(void) +{ + int position; + rt_uint32_t level; + struct heap_mem *mem; + level = rt_hw_interrupt_disable(); + for (mem = (struct heap_mem*)heap_ptr; mem != heap_end; mem = (struct heap_mem*)&heap_ptr[mem->next]) + { + position = (rt_uint32_t)mem - (rt_uint32_t)heap_ptr; + if (position < 0) goto __exit; + if (position > mem_size_aligned) goto __exit; + if (mem->magic != HEAP_MAGIC) goto __exit; + if (mem->used != 0 && mem->used != 1) goto __exit; + } + rt_hw_interrupt_enable(level); + + return 0; +__exit: + rt_kprintf("Memory block wrong:\n"); + rt_kprintf("address: 0x%08x\n", mem); + rt_kprintf(" magic: 0x%04x\n", mem->magic); + rt_kprintf(" used: %d\n", mem->used); + rt_kprintf(" size: %d\n", mem->next - position - SIZEOF_STRUCT_MEM); + rt_hw_interrupt_enable(level); + + return 0; +} +MSH_CMD_EXPORT(memcheck, check memory data); + +int memtrace(int argc, char** argv) +{ + struct heap_mem *mem; + + list_mem(); + + rt_kprintf("\nmemory heap address:\n"); + rt_kprintf("heap_ptr: 0x%08x\n", heap_ptr); + rt_kprintf("lfree : 0x%08x\n", lfree); + rt_kprintf("heap_end: 0x%08x\n", heap_end); + + rt_kprintf("\n--memory item information --\n"); + for (mem = (struct heap_mem*)heap_ptr; mem != heap_end; mem = (struct heap_mem*)&heap_ptr[mem->next]) + { + int position = (rt_uint32_t)mem - (rt_uint32_t)heap_ptr; + int size; + + rt_kprintf("[0x%08x - ", mem); + + size = mem->next - position - SIZEOF_STRUCT_MEM; + if (size < 1024) + rt_kprintf("%5d", size); + else if (size < 1024 * 1024) + rt_kprintf("%4dK", size / 1024); + else + rt_kprintf("%4dM", size / (1024 * 1024)); + + rt_kprintf("] %c%c%c%c", mem->thread[0], mem->thread[1], mem->thread[2], mem->thread[3]); + if (mem->magic != HEAP_MAGIC) + rt_kprintf(": ***\n"); + else + rt_kprintf("\n"); + } + + return 0; +} +MSH_CMD_EXPORT(memtrace, dump memory trace information); +#endif /* end of RT_USING_MEMTRACE */ +#endif /* end of RT_USING_FINSH */ + #endif /**@}*/