Pārlūkot izejas kodu

[Kernel] Add memory trace for small memory management

Bernard Xiong 7 gadi atpakaļ
vecāks
revīzija
5326bd55a5
2 mainītis faili ar 133 papildinājumiem un 1 dzēšanām
  1. 16 0
      src/Kconfig
  2. 117 1
      src/mem.c

+ 16 - 0
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

+ 117 - 1
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
 
 /**@}*/