mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 16:27:35 +00:00
Kernel: Dump backtrace to debugger for DefaultSignalAction::DumpCore.
This makes assertion failures generate backtraces again. Sorry to everyone who suffered from the lack of backtraces lately. :^) We share code with the /proc/PID/stack implementation. You can now get the current backtrace for a Thread via Thread::backtrace(), and all the traces for a Process via Process::backtrace().
This commit is contained in:
parent
a599317624
commit
4316fa8123
5 changed files with 62 additions and 32 deletions
|
@ -314,37 +314,7 @@ ByteBuffer procfs$pid_stack(InodeIdentifier identifier)
|
||||||
if (!handle)
|
if (!handle)
|
||||||
return {};
|
return {};
|
||||||
auto& process = handle->process();
|
auto& process = handle->process();
|
||||||
ProcessPagingScope paging_scope(process);
|
return process.backtrace(*handle).to_byte_buffer();
|
||||||
struct RecognizedSymbol {
|
|
||||||
u32 address;
|
|
||||||
const KSym* ksym;
|
|
||||||
};
|
|
||||||
StringBuilder builder;
|
|
||||||
process.for_each_thread([&](Thread& thread) {
|
|
||||||
builder.appendf("Thread %d:\n", thread.tid());
|
|
||||||
Vector<RecognizedSymbol, 64> recognized_symbols;
|
|
||||||
recognized_symbols.append({ thread.tss().eip, ksymbolicate(thread.tss().eip) });
|
|
||||||
for (u32* stack_ptr = (u32*)thread.frame_ptr(); process.validate_read_from_kernel(VirtualAddress((u32)stack_ptr)); stack_ptr = (u32*)*stack_ptr) {
|
|
||||||
u32 retaddr = stack_ptr[1];
|
|
||||||
recognized_symbols.append({ retaddr, ksymbolicate(retaddr) });
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& symbol : recognized_symbols) {
|
|
||||||
if (!symbol.address)
|
|
||||||
break;
|
|
||||||
if (!symbol.ksym) {
|
|
||||||
builder.appendf("%p\n", symbol.address);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
unsigned offset = symbol.address - symbol.ksym->address;
|
|
||||||
if (symbol.ksym->address == ksym_highest_address && offset > 4096)
|
|
||||||
builder.appendf("%p\n", symbol.address);
|
|
||||||
else
|
|
||||||
builder.appendf("%p %s +%u\n", symbol.address, symbol.ksym->name, offset);
|
|
||||||
}
|
|
||||||
return IterationDecision::Continue;
|
|
||||||
});
|
|
||||||
return builder.to_byte_buffer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteBuffer procfs$pid_regs(InodeIdentifier identifier)
|
ByteBuffer procfs$pid_regs(InodeIdentifier identifier)
|
||||||
|
|
|
@ -1279,6 +1279,7 @@ int Process::sys$kill(pid_t pid, int signal)
|
||||||
ASSERT(pid != -1);
|
ASSERT(pid != -1);
|
||||||
}
|
}
|
||||||
if (pid == m_pid) {
|
if (pid == m_pid) {
|
||||||
|
// FIXME: If we ignore this signal anyway, we don't need to block here, right?
|
||||||
current->send_signal(signal, this);
|
current->send_signal(signal, this);
|
||||||
(void)current->block<Thread::SemiPermanentBlocker>(Thread::SemiPermanentBlocker::Reason::Signal);
|
(void)current->block<Thread::SemiPermanentBlocker>(Thread::SemiPermanentBlocker::Reason::Signal);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2752,3 +2753,14 @@ int Process::sys$dbgputstr(const u8* characters, int length)
|
||||||
IO::out8(0xe9, characters[i]);
|
IO::out8(0xe9, characters[i]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String Process::backtrace(ProcessInspectionHandle& handle) const
|
||||||
|
{
|
||||||
|
StringBuilder builder;
|
||||||
|
for_each_thread([&](Thread& thread) {
|
||||||
|
builder.appendf("Thread %d:\n", thread.tid());
|
||||||
|
builder.append(thread.backtrace(handle));
|
||||||
|
return IterationDecision::Continue;
|
||||||
|
});
|
||||||
|
return builder.to_string();
|
||||||
|
}
|
||||||
|
|
|
@ -56,6 +56,8 @@ public:
|
||||||
Ring3 = 3,
|
Ring3 = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
String backtrace(ProcessInspectionHandle&) const;
|
||||||
|
|
||||||
bool is_dead() const { return m_dead; }
|
bool is_dead() const { return m_dead; }
|
||||||
|
|
||||||
Thread::State state() const { return main_thread().state(); }
|
Thread::State state() const { return main_thread().state(); }
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <AK/StringBuilder.h>
|
||||||
#include <Kernel/FileSystem/FileDescription.h>
|
#include <Kernel/FileSystem/FileDescription.h>
|
||||||
#include <Kernel/Process.h>
|
#include <Kernel/Process.h>
|
||||||
#include <Kernel/Scheduler.h>
|
#include <Kernel/Scheduler.h>
|
||||||
|
@ -319,7 +320,12 @@ ShouldUnblockThread Thread::dispatch_signal(u8 signal)
|
||||||
case DefaultSignalAction::Stop:
|
case DefaultSignalAction::Stop:
|
||||||
set_state(Stopped);
|
set_state(Stopped);
|
||||||
return ShouldUnblockThread::No;
|
return ShouldUnblockThread::No;
|
||||||
case DefaultSignalAction::DumpCore:
|
case DefaultSignalAction::DumpCore: {
|
||||||
|
ProcessInspectionHandle handle(process());
|
||||||
|
dbg() << "Dumping \"Core\" for " << process();
|
||||||
|
dbg() << process().backtrace(handle);
|
||||||
|
}
|
||||||
|
[[fallthrough]];
|
||||||
case DefaultSignalAction::Terminate:
|
case DefaultSignalAction::Terminate:
|
||||||
m_process.terminate_due_to_signal(signal);
|
m_process.terminate_due_to_signal(signal);
|
||||||
return ShouldUnblockThread::No;
|
return ShouldUnblockThread::No;
|
||||||
|
@ -543,3 +549,35 @@ void Thread::set_state(State new_state)
|
||||||
Scheduler::update_state_for_thread(*this);
|
Scheduler::update_state_for_thread(*this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String Thread::backtrace(ProcessInspectionHandle&) const
|
||||||
|
{
|
||||||
|
auto& process = const_cast<Process&>(this->process());
|
||||||
|
ProcessPagingScope paging_scope(process);
|
||||||
|
struct RecognizedSymbol {
|
||||||
|
u32 address;
|
||||||
|
const KSym* ksym;
|
||||||
|
};
|
||||||
|
StringBuilder builder;
|
||||||
|
Vector<RecognizedSymbol, 64> recognized_symbols;
|
||||||
|
recognized_symbols.append({ tss().eip, ksymbolicate(tss().eip) });
|
||||||
|
for (u32* stack_ptr = (u32*)frame_ptr(); process.validate_read_from_kernel(VirtualAddress((u32)stack_ptr)); stack_ptr = (u32*)*stack_ptr) {
|
||||||
|
u32 retaddr = stack_ptr[1];
|
||||||
|
recognized_symbols.append({ retaddr, ksymbolicate(retaddr) });
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& symbol : recognized_symbols) {
|
||||||
|
if (!symbol.address)
|
||||||
|
break;
|
||||||
|
if (!symbol.ksym) {
|
||||||
|
builder.appendf("%p\n", symbol.address);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
unsigned offset = symbol.address - symbol.ksym->address;
|
||||||
|
if (symbol.ksym->address == ksym_highest_address && offset > 4096)
|
||||||
|
builder.appendf("%p\n", symbol.address);
|
||||||
|
else
|
||||||
|
builder.appendf("%p %s +%u\n", symbol.address, symbol.ksym->name, offset);
|
||||||
|
}
|
||||||
|
return builder.to_string();
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
class Alarm;
|
class Alarm;
|
||||||
class FileDescription;
|
class FileDescription;
|
||||||
class Process;
|
class Process;
|
||||||
|
class ProcessInspectionHandle;
|
||||||
class Region;
|
class Region;
|
||||||
|
|
||||||
enum class ShouldUnblockThread {
|
enum class ShouldUnblockThread {
|
||||||
|
@ -49,6 +50,8 @@ public:
|
||||||
Process& process() { return m_process; }
|
Process& process() { return m_process; }
|
||||||
const Process& process() const { return m_process; }
|
const Process& process() const { return m_process; }
|
||||||
|
|
||||||
|
String backtrace(ProcessInspectionHandle&) const;
|
||||||
|
|
||||||
void finalize();
|
void finalize();
|
||||||
|
|
||||||
enum State : u8 {
|
enum State : u8 {
|
||||||
|
@ -205,6 +208,7 @@ public:
|
||||||
|
|
||||||
u16 selector() const { return m_far_ptr.selector; }
|
u16 selector() const { return m_far_ptr.selector; }
|
||||||
TSS32& tss() { return m_tss; }
|
TSS32& tss() { return m_tss; }
|
||||||
|
const TSS32& tss() const { return m_tss; }
|
||||||
State state() const { return m_state; }
|
State state() const { return m_state; }
|
||||||
const char* state_string() const;
|
const char* state_string() const;
|
||||||
u32 ticks() const { return m_ticks; }
|
u32 ticks() const { return m_ticks; }
|
||||||
|
@ -371,3 +375,7 @@ inline IterationDecision Thread::for_each_in_state(State state, Callback callbac
|
||||||
return Scheduler::for_each_nonrunnable(new_callback);
|
return Scheduler::for_each_nonrunnable(new_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const LogStream& operator<<(const LogStream& stream, const Thread& value)
|
||||||
|
{
|
||||||
|
return stream << "Thread{" << &value << "}(" << value.pid() << ":" << value.tid() << ")";
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue