Przeglądaj źródła

UserspaceEmulator: Capture backtraces of malloc/free events

This lets us show backtraces for each leaked mallocation in the leak
report at the end. :^)
Andreas Kling 5 lat temu
rodzic
commit
441918be7e

+ 21 - 11
DevTools/UserspaceEmulator/Emulator.cpp

@@ -188,24 +188,34 @@ bool Emulator::is_in_malloc_or_free() const
 
 static pid_t s_pid = getpid();
 
-void Emulator::dump_backtrace()
+Vector<FlatPtr> Emulator::raw_backtrace()
 {
-    u32 offset = 0;
-    String symbol = m_elf->symbolicate(m_cpu.eip(), &offset);
-
-    dbgprintf("==%d==    %#08x  %s +%#x\n", s_pid, m_cpu.eip(), symbol.characters(), offset);
+    Vector<FlatPtr> backtrace;
+    backtrace.append(m_cpu.eip());
 
     u32 frame_ptr = m_cpu.ebp();
     while (frame_ptr) {
         u32 ret_ptr = m_mmu.read32({ 0x20, frame_ptr + 4 });
         if (!ret_ptr)
-            return;
-        symbol = m_elf->symbolicate(ret_ptr, &offset);
-        if (!symbol.is_null())
-            dbgprintf("==%d==    %#08x  %s +%#x\n", s_pid, ret_ptr, symbol.characters(), offset);
-
+            break;
+        backtrace.append(ret_ptr);
         frame_ptr = m_mmu.read32({ 0x20, frame_ptr });
     }
+    return backtrace;
+}
+
+void Emulator::dump_backtrace(const Vector<FlatPtr>& backtrace)
+{
+    for (auto& address : backtrace) {
+        u32 offset = 0;
+        String symbol = m_elf->symbolicate(address, &offset);
+        dbgprintf("==%d==    %#08x  %s +%#x\n", s_pid, m_cpu.eip(), symbol.characters(), offset);
+    }
+}
+
+void Emulator::dump_backtrace()
+{
+    dump_backtrace(raw_backtrace());
 }
 
 u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3)
@@ -306,7 +316,7 @@ u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3)
     case SC_clock_gettime:
         return virt$clock_gettime(arg1, arg2);
     case SC_getrandom:
-        return virt$getrandom(arg1, arg2, arg3)       ;
+        return virt$getrandom(arg1, arg2, arg3);
 
     default:
         warn() << "Unimplemented syscall: " << Syscall::to_string((Syscall::Function)function);

+ 2 - 0
DevTools/UserspaceEmulator/Emulator.h

@@ -46,6 +46,8 @@ public:
 
     bool load_elf();
     void dump_backtrace();
+    void dump_backtrace(const Vector<FlatPtr>&);
+    Vector<FlatPtr> raw_backtrace();
 
     int exec();
     u32 virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3);

+ 6 - 3
DevTools/UserspaceEmulator/MallocTracer.cpp

@@ -45,7 +45,7 @@ void MallocTracer::target_did_malloc(Badge<SoftCPU>, FlatPtr address, size_t siz
         existing_mallocation->freed = false;
         return;
     }
-    m_mallocations.append({ address, size });
+    m_mallocations.append({ address, size, false, Emulator::the().raw_backtrace(), Vector<FlatPtr>() });
 }
 
 void MallocTracer::target_did_free(Badge<SoftCPU>, FlatPtr address)
@@ -60,8 +60,10 @@ void MallocTracer::target_did_free(Badge<SoftCPU>, FlatPtr address)
                 dbgprintf("==%d==  \033[31;1mDouble free()\033[0m, %p\n", s_pid, address);
                 dbgprintf("==%d==  Address %p has already been passed to free()\n", s_pid, address);
                 Emulator::the().dump_backtrace();
+            } else {
+                mallocation.freed = true;
+                mallocation.free_backtrace = Emulator::the().raw_backtrace();
             }
-            mallocation.freed = true;
             return;
         }
     }
@@ -179,9 +181,10 @@ void MallocTracer::dump_leak_report()
         ++leaks_found;
         dbgprintf("\n");
         dbgprintf("==%d==  \033[31;1mLeak\033[0m, %zu-byte allocation at address %p\n", s_pid, mallocation.size, mallocation.address);
+        Emulator::the().dump_backtrace(mallocation.malloc_backtrace);
     }
 
-    dbgprintf("==%d==  %zu leak(s) found\n", s_pid, leaks_found);
+    dbgprintf("==%d==  \033[%d;1m%zu leak(s) found\033[0m\n", s_pid, leaks_found ? 31 : 32, leaks_found);
 }
 
 }

+ 3 - 0
DevTools/UserspaceEmulator/MallocTracer.h

@@ -56,6 +56,9 @@ private:
         FlatPtr address { 0 };
         size_t size { 0 };
         bool freed { false };
+
+        Vector<FlatPtr> malloc_backtrace;
+        Vector<FlatPtr> free_backtrace;
     };
 
     Mallocation* find_mallocation(FlatPtr);