Просмотр исходного кода

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.
Andreas Kling 6 лет назад
Родитель
Сommit
c928b06218

+ 1 - 0
Kernel/.gitignore

@@ -2,3 +2,4 @@
 .floppy-image
 Boot/boot.bin
 kernel
+kernel.map

+ 1 - 0
Kernel/Console.h

@@ -1,5 +1,6 @@
 #pragma once
 
+#include <AK/Compiler.h>
 #include <VirtualFileSystem/CharacterDevice.h>
 
 class Console final : public CharacterDevice {

+ 6 - 3
Kernel/Makefile

@@ -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)

+ 36 - 0
Kernel/ProcFileSystem.cpp

@@ -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)

+ 6 - 6
Kernel/Task.cpp

@@ -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.

+ 5 - 1
Kernel/Task.h

@@ -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 };

BIN
Kernel/_fs_contents


+ 51 - 0
Kernel/init.cpp

@@ -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

+ 2 - 2
Kernel/kmalloc.cpp

@@ -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 - 0
Kernel/mkmap.sh

@@ -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

+ 1 - 0
Kernel/sync-sh

@@ -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

+ 9 - 0
Kernel/system.h

@@ -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
 {

+ 1 - 1
Userland/cat.cpp

@@ -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;

+ 6 - 0
VirtualFileSystem/SyntheticFileSystem.cpp

@@ -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());