mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 22:07:34 +00:00
UserspaceEmulator: Capture backtraces of malloc/free events
This lets us show backtraces for each leaked mallocation in the leak report at the end. :^)
This commit is contained in:
parent
f6584bfc36
commit
441918be7e
4 changed files with 32 additions and 14 deletions
|
@ -188,24 +188,34 @@ bool Emulator::is_in_malloc_or_free() const
|
||||||
|
|
||||||
static pid_t s_pid = getpid();
|
static pid_t s_pid = getpid();
|
||||||
|
|
||||||
void Emulator::dump_backtrace()
|
Vector<FlatPtr> Emulator::raw_backtrace()
|
||||||
{
|
{
|
||||||
u32 offset = 0;
|
Vector<FlatPtr> backtrace;
|
||||||
String symbol = m_elf->symbolicate(m_cpu.eip(), &offset);
|
backtrace.append(m_cpu.eip());
|
||||||
|
|
||||||
dbgprintf("==%d== %#08x %s +%#x\n", s_pid, m_cpu.eip(), symbol.characters(), offset);
|
|
||||||
|
|
||||||
u32 frame_ptr = m_cpu.ebp();
|
u32 frame_ptr = m_cpu.ebp();
|
||||||
while (frame_ptr) {
|
while (frame_ptr) {
|
||||||
u32 ret_ptr = m_mmu.read32({ 0x20, frame_ptr + 4 });
|
u32 ret_ptr = m_mmu.read32({ 0x20, frame_ptr + 4 });
|
||||||
if (!ret_ptr)
|
if (!ret_ptr)
|
||||||
return;
|
break;
|
||||||
symbol = m_elf->symbolicate(ret_ptr, &offset);
|
backtrace.append(ret_ptr);
|
||||||
if (!symbol.is_null())
|
|
||||||
dbgprintf("==%d== %#08x %s +%#x\n", s_pid, ret_ptr, symbol.characters(), offset);
|
|
||||||
|
|
||||||
frame_ptr = m_mmu.read32({ 0x20, frame_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)
|
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:
|
case SC_clock_gettime:
|
||||||
return virt$clock_gettime(arg1, arg2);
|
return virt$clock_gettime(arg1, arg2);
|
||||||
case SC_getrandom:
|
case SC_getrandom:
|
||||||
return virt$getrandom(arg1, arg2, arg3) ;
|
return virt$getrandom(arg1, arg2, arg3);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
warn() << "Unimplemented syscall: " << Syscall::to_string((Syscall::Function)function);
|
warn() << "Unimplemented syscall: " << Syscall::to_string((Syscall::Function)function);
|
||||||
|
|
|
@ -46,6 +46,8 @@ public:
|
||||||
|
|
||||||
bool load_elf();
|
bool load_elf();
|
||||||
void dump_backtrace();
|
void dump_backtrace();
|
||||||
|
void dump_backtrace(const Vector<FlatPtr>&);
|
||||||
|
Vector<FlatPtr> raw_backtrace();
|
||||||
|
|
||||||
int exec();
|
int exec();
|
||||||
u32 virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3);
|
u32 virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3);
|
||||||
|
|
|
@ -45,7 +45,7 @@ void MallocTracer::target_did_malloc(Badge<SoftCPU>, FlatPtr address, size_t siz
|
||||||
existing_mallocation->freed = false;
|
existing_mallocation->freed = false;
|
||||||
return;
|
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)
|
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== \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);
|
dbgprintf("==%d== Address %p has already been passed to free()\n", s_pid, address);
|
||||||
Emulator::the().dump_backtrace();
|
Emulator::the().dump_backtrace();
|
||||||
|
} else {
|
||||||
|
mallocation.freed = true;
|
||||||
|
mallocation.free_backtrace = Emulator::the().raw_backtrace();
|
||||||
}
|
}
|
||||||
mallocation.freed = true;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,9 +181,10 @@ void MallocTracer::dump_leak_report()
|
||||||
++leaks_found;
|
++leaks_found;
|
||||||
dbgprintf("\n");
|
dbgprintf("\n");
|
||||||
dbgprintf("==%d== \033[31;1mLeak\033[0m, %zu-byte allocation at address %p\n", s_pid, mallocation.size, mallocation.address);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,9 @@ private:
|
||||||
FlatPtr address { 0 };
|
FlatPtr address { 0 };
|
||||||
size_t size { 0 };
|
size_t size { 0 };
|
||||||
bool freed { false };
|
bool freed { false };
|
||||||
|
|
||||||
|
Vector<FlatPtr> malloc_backtrace;
|
||||||
|
Vector<FlatPtr> free_backtrace;
|
||||||
};
|
};
|
||||||
|
|
||||||
Mallocation* find_mallocation(FlatPtr);
|
Mallocation* find_mallocation(FlatPtr);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue