mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-04 05:20:30 +00:00
Add a very hackish /proc/PID/stack.
It walks the stack and identifies anything that looks like a kernel symbol. This could be a lot more sophisticated.
This commit is contained in:
parent
81627cf7d5
commit
c928b06218
Notes:
sideshowbarker
2024-07-19 18:37:59 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/c928b062180
14 changed files with 130 additions and 13 deletions
1
Kernel/.gitignore
vendored
1
Kernel/.gitignore
vendored
|
@ -2,3 +2,4 @@
|
|||
.floppy-image
|
||||
Boot/boot.bin
|
||||
kernel
|
||||
kernel.map
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Compiler.h>
|
||||
#include <VirtualFileSystem/CharacterDevice.h>
|
||||
|
||||
class Console final : public CharacterDevice {
|
||||
|
|
|
@ -56,8 +56,8 @@ ARCH_FLAGS =
|
|||
STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib
|
||||
KERNEL_FLAGS = -ffreestanding -fno-stack-protector -fno-ident
|
||||
WARNING_FLAGS = -Wextra -Wall -Wundef -Wcast-qual -Wwrite-strings
|
||||
FLAVOR_FLAGS = -fomit-frame-pointer -mregparm=3 -march=i386 -m32 -fno-exceptions -fno-rtti -ffunction-sections -fdata-sections -fmerge-all-constants -fno-unroll-loops -falign-functions=1 -falign-jumps=1 -falign-loops=1 -fno-pie -fno-pic
|
||||
#FLAVOR_FLAGS = -fomit-frame-pointer -mregparm=3 -march=i386 -m32 -fno-exceptions -fno-rtti -ffunction-sections -fdata-sections
|
||||
FLAVOR_FLAGS = -mregparm=3 -march=i386 -m32 -fno-exceptions -fno-rtti -ffunction-sections -fdata-sections -fmerge-all-constants -fno-unroll-loops -falign-functions=1 -falign-jumps=1 -falign-loops=1 -fno-pie -fno-pic
|
||||
#FLAVOR_FLAGS = -mregparm=3 -march=i386 -m32 -fno-exceptions -fno-rtti -ffunction-sections -fdata-sections
|
||||
OPTIMIZATION_FLAGS = -Os -fno-asynchronous-unwind-tables
|
||||
INCLUDE_FLAGS = -I.. -I.
|
||||
|
||||
|
@ -71,7 +71,10 @@ LD = ld
|
|||
LDFLAGS = -T linker.ld --strip-debug -melf_i386 --gc-sections --build-id=none -z norelro -z now
|
||||
|
||||
|
||||
all: $(KERNEL) $(IMAGE)
|
||||
all: $(KERNEL) $(IMAGE) kernel.map
|
||||
|
||||
kernel.map: kernel
|
||||
@echo "MKMAP $@"; sh mkmap.sh
|
||||
|
||||
$(KERNEL): $(OBJS)
|
||||
@echo "LD $@"; $(LD) $(LDFLAGS) -o $@ -Ttext 0x10000 $(OBJS)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "ProcFileSystem.h"
|
||||
#include "Task.h"
|
||||
#include <VirtualFileSystem/VirtualFileSystem.h>
|
||||
#include "system.h"
|
||||
|
||||
static ProcFileSystem* s_the;
|
||||
|
||||
|
@ -48,6 +49,41 @@ void ProcFileSystem::addProcess(Task& task)
|
|||
*ptr = '\0';
|
||||
return ByteBuffer::copy((byte*)buffer, ptr - buffer);
|
||||
}), dir.index());
|
||||
addFile(createGeneratedFile("stack", [&task] {
|
||||
InterruptDisabler disabler;
|
||||
auto& syms = ksyms();
|
||||
dword firstKsymAddress = syms.first().address;
|
||||
dword lastKsymAddress = syms.last().address;
|
||||
struct RecognizedSymbol {
|
||||
dword address;
|
||||
const char* name;
|
||||
dword offset;
|
||||
};
|
||||
Vector<RecognizedSymbol> recognizedSymbols;
|
||||
size_t bytesNeeded = 0;
|
||||
for (dword* stackPtr = (dword*)task.stackPtr(); (dword)stackPtr < task.stackTop(); ++stackPtr) {
|
||||
if (*stackPtr < firstKsymAddress || *stackPtr > lastKsymAddress)
|
||||
continue;
|
||||
const char* name = nullptr;
|
||||
unsigned offset = 0;
|
||||
for (unsigned i = 0; i < syms.size(); ++i) {
|
||||
if (*stackPtr < syms[i+1].address) {
|
||||
name = syms[i].name.characters();
|
||||
offset = *stackPtr - syms[i].address;
|
||||
bytesNeeded += syms[i].name.length() + 8 + 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
recognizedSymbols.append({ *stackPtr, name, offset });
|
||||
}
|
||||
auto buffer = ByteBuffer::createUninitialized(bytesNeeded);
|
||||
char* ptr = (char*)buffer.pointer();
|
||||
for (auto& symbol : recognizedSymbols) {
|
||||
kprintf("%p %s +%u\n", symbol.address, symbol.name, symbol.offset);
|
||||
}
|
||||
buffer.trim(ptr - (char*)buffer.pointer());
|
||||
return buffer;
|
||||
}), dir.index());
|
||||
}
|
||||
|
||||
void ProcFileSystem::removeProcess(Task& task)
|
||||
|
|
|
@ -378,21 +378,21 @@ Task::Task(String&& name, uid_t uid, gid_t gid, pid_t parentPID, RingLevel ring)
|
|||
// FIXME: This memory is leaked.
|
||||
// But uh, there's also no kernel task termination, so I guess it's not technically leaked...
|
||||
dword stackBottom = (dword)kmalloc(defaultStackSize);
|
||||
m_stackTop = (stackBottom + defaultStackSize) & 0xffffff8;
|
||||
m_tss.esp = m_stackTop;
|
||||
m_stackTop0 = (stackBottom + defaultStackSize) & 0xffffff8;
|
||||
m_tss.esp = m_stackTop0;
|
||||
} else {
|
||||
auto* region = allocateRegion(defaultStackSize, "stack");
|
||||
ASSERT(region);
|
||||
m_stackTop = region->linearAddress.offset(defaultStackSize).get() & 0xfffffff8;
|
||||
m_stackTop3 = region->linearAddress.offset(defaultStackSize).get() & 0xfffffff8;
|
||||
m_tss.esp = m_stackTop3;
|
||||
}
|
||||
m_tss.esp = m_stackTop;
|
||||
|
||||
if (isRing3()) {
|
||||
// Ring3 tasks need a separate stack for Ring0.
|
||||
m_kernelStack = kmalloc(defaultStackSize);
|
||||
DWORD ring0StackTop = ((DWORD)m_kernelStack + defaultStackSize) & 0xffffff8;
|
||||
m_stackTop0 = ((DWORD)m_kernelStack + defaultStackSize) & 0xffffff8;
|
||||
m_tss.ss0 = 0x10;
|
||||
m_tss.esp0 = ring0StackTop;
|
||||
m_tss.esp0 = m_stackTop0;
|
||||
}
|
||||
|
||||
// HACK: Ring2 SS in the TSS is the current PID.
|
||||
|
|
|
@ -122,6 +122,9 @@ public:
|
|||
|
||||
size_t fileHandleCount() const { return m_fileHandles.size(); }
|
||||
|
||||
dword stackPtr() const { return m_tss.esp; }
|
||||
dword stackTop() const { return m_tss.ss == 0x10 ? m_stackTop0 : m_stackTop3; }
|
||||
|
||||
private:
|
||||
friend class MemoryManager;
|
||||
friend bool scheduleNewTask();
|
||||
|
@ -140,7 +143,8 @@ private:
|
|||
gid_t m_gid { 0 };
|
||||
DWORD m_ticks { 0 };
|
||||
DWORD m_ticksLeft { 0 };
|
||||
DWORD m_stackTop { 0 };
|
||||
DWORD m_stackTop0 { 0 };
|
||||
DWORD m_stackTop3 { 0 };
|
||||
FarPtr m_farPtr;
|
||||
State m_state { Invalid };
|
||||
DWORD m_wakeupTime { 0 };
|
||||
|
|
Binary file not shown.
|
@ -28,6 +28,7 @@
|
|||
#include "RTC.h"
|
||||
|
||||
#define TEST_VFS
|
||||
#define KERNEL_MAP
|
||||
//#define STRESS_TEST_SPAWNING
|
||||
//#define TEST_ELF_LOADER
|
||||
//#define TEST_CRASHY_USER_PROCESSES
|
||||
|
@ -49,6 +50,43 @@ void banner()
|
|||
kprintf("\n");
|
||||
}
|
||||
|
||||
static byte parseHexDigit(char nibble)
|
||||
{
|
||||
if (nibble >= '0' && nibble <= '9')
|
||||
return nibble - '0';
|
||||
ASSERT(nibble >= 'a' && nibble <= 'f');
|
||||
return 10 + (nibble - 'a');
|
||||
}
|
||||
|
||||
static Vector<KSym>* s_ksyms;
|
||||
|
||||
Vector<KSym>& ksyms()
|
||||
{
|
||||
return *s_ksyms;
|
||||
}
|
||||
|
||||
static void loadKernelMap(const ByteBuffer& buffer)
|
||||
{
|
||||
s_ksyms = new Vector<KSym>;
|
||||
auto* bufptr = (const char*)buffer.pointer();
|
||||
auto* startOfName = bufptr;
|
||||
dword address = 0;
|
||||
|
||||
while (bufptr < buffer.endPointer()) {
|
||||
for (unsigned i = 0; i < 8; ++i)
|
||||
address = (address << 4) | parseHexDigit(*(bufptr++));
|
||||
bufptr += 3;
|
||||
startOfName = bufptr;
|
||||
while (*(++bufptr)) {
|
||||
if (*bufptr == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ksyms().append({ address, String(startOfName, bufptr - startOfName) });
|
||||
++bufptr;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST_CRASHY_USER_PROCESSES
|
||||
static void user_main() NORETURN;
|
||||
static void user_main()
|
||||
|
@ -108,6 +146,19 @@ static void init_stage2()
|
|||
|
||||
vfs->mountRoot(e2fs.copyRef());
|
||||
|
||||
#ifdef KERNEL_MAP
|
||||
{
|
||||
auto handle = vfs->open("/kernel.map");
|
||||
if (!handle) {
|
||||
kprintf("Failed to open /kernel.map\n");
|
||||
} else {
|
||||
auto buffer = handle->readEntireFile();
|
||||
ASSERT(buffer);
|
||||
loadKernelMap(buffer);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
vfs->mount(ProcFileSystem::the(), "/proc");
|
||||
|
||||
#endif
|
||||
|
|
|
@ -107,10 +107,10 @@ kmalloc( DWORD size )
|
|||
}
|
||||
}
|
||||
|
||||
kprintf( "kmalloc(): PANIC! Out of memory (no suitable block)" );
|
||||
kprintf("kmalloc(): PANIC! Out of memory (no suitable block for size %u)\n", size);
|
||||
HANG;
|
||||
|
||||
return 0L;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PUBLIC void
|
||||
|
|
5
Kernel/mkmap.sh
Normal file
5
Kernel/mkmap.sh
Normal file
|
@ -0,0 +1,5 @@
|
|||
#!/bin/sh
|
||||
tmp=$(mktemp)
|
||||
nm -C kernel > $tmp
|
||||
perl -lpe '$_=hex' $tmp | paste -d" " - $tmp | sort -n | cut -d" " -f 2- > kernel.map
|
||||
rm $tmp
|
|
@ -12,5 +12,6 @@ cp ../Userland/false mnt/bin/false
|
|||
cp ../Userland/hostname mnt/bin/hostname
|
||||
cp ../Userland/cat mnt/bin/cat
|
||||
cp ../Userland/uname mnt/bin/uname
|
||||
cp kernel.map mnt/
|
||||
umount mnt
|
||||
sync
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include <AK/Vector.h>
|
||||
#include <AK/String.h>
|
||||
|
||||
struct KSym {
|
||||
dword address;
|
||||
String name;
|
||||
};
|
||||
|
||||
Vector<KSym>& ksyms() PURE;
|
||||
|
||||
struct system_t
|
||||
{
|
||||
|
|
|
@ -15,7 +15,7 @@ int main(int argc, char** argv)
|
|||
return 1;
|
||||
}
|
||||
for (;;) {
|
||||
char buf[128];
|
||||
char buf[4096];
|
||||
ssize_t nread = read(fd, buf, sizeof(buf));
|
||||
if (nread == 0)
|
||||
break;
|
||||
|
|
|
@ -79,6 +79,7 @@ auto SyntheticFileSystem::createGeneratedFile(String&& name, Function<ByteBuffer
|
|||
|
||||
InodeIdentifier SyntheticFileSystem::addFile(OwnPtr<File>&& file, InodeIndex parent)
|
||||
{
|
||||
ASSERT_INTERRUPTS_DISABLED();
|
||||
ASSERT(file);
|
||||
auto it = m_inodes.find(parent);
|
||||
ASSERT(it != m_inodes.end());
|
||||
|
@ -92,6 +93,7 @@ InodeIdentifier SyntheticFileSystem::addFile(OwnPtr<File>&& file, InodeIndex par
|
|||
|
||||
bool SyntheticFileSystem::removeFile(InodeIndex inode)
|
||||
{
|
||||
ASSERT_INTERRUPTS_DISABLED();
|
||||
auto it = m_inodes.find(inode);
|
||||
if (it == m_inodes.end())
|
||||
return false;
|
||||
|
@ -127,6 +129,7 @@ InodeIdentifier SyntheticFileSystem::rootInode() const
|
|||
|
||||
bool SyntheticFileSystem::enumerateDirectoryInode(InodeIdentifier inode, Function<bool(const DirectoryEntry&)> callback) const
|
||||
{
|
||||
InterruptDisabler disabler;
|
||||
ASSERT(inode.fileSystemID() == id());
|
||||
#ifdef SYNTHFS_DEBUG
|
||||
kprintf("[synthfs] enumerateDirectoryInode %u\n", inode.index());
|
||||
|
@ -150,6 +153,7 @@ bool SyntheticFileSystem::enumerateDirectoryInode(InodeIdentifier inode, Functio
|
|||
|
||||
InodeMetadata SyntheticFileSystem::inodeMetadata(InodeIdentifier inode) const
|
||||
{
|
||||
InterruptDisabler disabler;
|
||||
ASSERT(inode.fileSystemID() == id());
|
||||
#ifdef SYNTHFS_DEBUG
|
||||
kprintf("[synthfs] inodeMetadata(%u)\n", inode.index());
|
||||
|
@ -186,6 +190,8 @@ bool SyntheticFileSystem::writeInode(InodeIdentifier, const ByteBuffer&)
|
|||
|
||||
Unix::ssize_t SyntheticFileSystem::readInodeBytes(InodeIdentifier inode, Unix::off_t offset, Unix::size_t count, byte* buffer) const
|
||||
{
|
||||
InterruptDisabler disabler;
|
||||
|
||||
ASSERT(inode.fileSystemID() == id());
|
||||
#ifdef SYNTHFS_DEBUG
|
||||
kprintf("[synthfs] readInode %u\n", inode.index());
|
||||
|
|
Loading…
Reference in a new issue