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:
Andreas Kling 2018-10-26 22:32:35 +02:00
parent 81627cf7d5
commit c928b06218
Notes: sideshowbarker 2024-07-19 18:37:59 +09:00
14 changed files with 130 additions and 13 deletions

1
Kernel/.gitignore vendored
View File

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

View File

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

View File

@ -56,8 +56,8 @@ ARCH_FLAGS =
STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib
KERNEL_FLAGS = -ffreestanding -fno-stack-protector -fno-ident KERNEL_FLAGS = -ffreestanding -fno-stack-protector -fno-ident
WARNING_FLAGS = -Wextra -Wall -Wundef -Wcast-qual -Wwrite-strings 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 = -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
OPTIMIZATION_FLAGS = -Os -fno-asynchronous-unwind-tables OPTIMIZATION_FLAGS = -Os -fno-asynchronous-unwind-tables
INCLUDE_FLAGS = -I.. -I. 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 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) $(KERNEL): $(OBJS)
@echo "LD $@"; $(LD) $(LDFLAGS) -o $@ -Ttext 0x10000 $(OBJS) @echo "LD $@"; $(LD) $(LDFLAGS) -o $@ -Ttext 0x10000 $(OBJS)

View File

@ -1,6 +1,7 @@
#include "ProcFileSystem.h" #include "ProcFileSystem.h"
#include "Task.h" #include "Task.h"
#include <VirtualFileSystem/VirtualFileSystem.h> #include <VirtualFileSystem/VirtualFileSystem.h>
#include "system.h"
static ProcFileSystem* s_the; static ProcFileSystem* s_the;
@ -48,6 +49,41 @@ void ProcFileSystem::addProcess(Task& task)
*ptr = '\0'; *ptr = '\0';
return ByteBuffer::copy((byte*)buffer, ptr - buffer); return ByteBuffer::copy((byte*)buffer, ptr - buffer);
}), dir.index()); }), 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) void ProcFileSystem::removeProcess(Task& task)

View File

@ -378,21 +378,21 @@ Task::Task(String&& name, uid_t uid, gid_t gid, pid_t parentPID, RingLevel ring)
// FIXME: This memory is leaked. // FIXME: This memory is leaked.
// But uh, there's also no kernel task termination, so I guess it's not technically leaked... // But uh, there's also no kernel task termination, so I guess it's not technically leaked...
dword stackBottom = (dword)kmalloc(defaultStackSize); dword stackBottom = (dword)kmalloc(defaultStackSize);
m_stackTop = (stackBottom + defaultStackSize) & 0xffffff8; m_stackTop0 = (stackBottom + defaultStackSize) & 0xffffff8;
m_tss.esp = m_stackTop; m_tss.esp = m_stackTop0;
} else { } else {
auto* region = allocateRegion(defaultStackSize, "stack"); auto* region = allocateRegion(defaultStackSize, "stack");
ASSERT(region); 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()) { if (isRing3()) {
// Ring3 tasks need a separate stack for Ring0. // Ring3 tasks need a separate stack for Ring0.
m_kernelStack = kmalloc(defaultStackSize); m_kernelStack = kmalloc(defaultStackSize);
DWORD ring0StackTop = ((DWORD)m_kernelStack + defaultStackSize) & 0xffffff8; m_stackTop0 = ((DWORD)m_kernelStack + defaultStackSize) & 0xffffff8;
m_tss.ss0 = 0x10; m_tss.ss0 = 0x10;
m_tss.esp0 = ring0StackTop; m_tss.esp0 = m_stackTop0;
} }
// HACK: Ring2 SS in the TSS is the current PID. // HACK: Ring2 SS in the TSS is the current PID.

View File

@ -122,6 +122,9 @@ public:
size_t fileHandleCount() const { return m_fileHandles.size(); } 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: private:
friend class MemoryManager; friend class MemoryManager;
friend bool scheduleNewTask(); friend bool scheduleNewTask();
@ -140,7 +143,8 @@ private:
gid_t m_gid { 0 }; gid_t m_gid { 0 };
DWORD m_ticks { 0 }; DWORD m_ticks { 0 };
DWORD m_ticksLeft { 0 }; DWORD m_ticksLeft { 0 };
DWORD m_stackTop { 0 }; DWORD m_stackTop0 { 0 };
DWORD m_stackTop3 { 0 };
FarPtr m_farPtr; FarPtr m_farPtr;
State m_state { Invalid }; State m_state { Invalid };
DWORD m_wakeupTime { 0 }; DWORD m_wakeupTime { 0 };

Binary file not shown.

View File

@ -28,6 +28,7 @@
#include "RTC.h" #include "RTC.h"
#define TEST_VFS #define TEST_VFS
#define KERNEL_MAP
//#define STRESS_TEST_SPAWNING //#define STRESS_TEST_SPAWNING
//#define TEST_ELF_LOADER //#define TEST_ELF_LOADER
//#define TEST_CRASHY_USER_PROCESSES //#define TEST_CRASHY_USER_PROCESSES
@ -49,6 +50,43 @@ void banner()
kprintf("\n"); 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 #ifdef TEST_CRASHY_USER_PROCESSES
static void user_main() NORETURN; static void user_main() NORETURN;
static void user_main() static void user_main()
@ -108,6 +146,19 @@ static void init_stage2()
vfs->mountRoot(e2fs.copyRef()); 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"); vfs->mount(ProcFileSystem::the(), "/proc");
#endif #endif

View File

@ -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; HANG;
return 0L; return nullptr;
} }
PUBLIC void PUBLIC void

5
Kernel/mkmap.sh Normal file
View 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

View File

@ -12,5 +12,6 @@ cp ../Userland/false mnt/bin/false
cp ../Userland/hostname mnt/bin/hostname cp ../Userland/hostname mnt/bin/hostname
cp ../Userland/cat mnt/bin/cat cp ../Userland/cat mnt/bin/cat
cp ../Userland/uname mnt/bin/uname cp ../Userland/uname mnt/bin/uname
cp kernel.map mnt/
umount mnt umount mnt
sync sync

View File

@ -1,6 +1,15 @@
#pragma once #pragma once
#include "types.h" #include "types.h"
#include <AK/Vector.h>
#include <AK/String.h>
struct KSym {
dword address;
String name;
};
Vector<KSym>& ksyms() PURE;
struct system_t struct system_t
{ {

View File

@ -15,7 +15,7 @@ int main(int argc, char** argv)
return 1; return 1;
} }
for (;;) { for (;;) {
char buf[128]; char buf[4096];
ssize_t nread = read(fd, buf, sizeof(buf)); ssize_t nread = read(fd, buf, sizeof(buf));
if (nread == 0) if (nread == 0)
break; break;

View File

@ -79,6 +79,7 @@ auto SyntheticFileSystem::createGeneratedFile(String&& name, Function<ByteBuffer
InodeIdentifier SyntheticFileSystem::addFile(OwnPtr<File>&& file, InodeIndex parent) InodeIdentifier SyntheticFileSystem::addFile(OwnPtr<File>&& file, InodeIndex parent)
{ {
ASSERT_INTERRUPTS_DISABLED();
ASSERT(file); ASSERT(file);
auto it = m_inodes.find(parent); auto it = m_inodes.find(parent);
ASSERT(it != m_inodes.end()); ASSERT(it != m_inodes.end());
@ -92,6 +93,7 @@ InodeIdentifier SyntheticFileSystem::addFile(OwnPtr<File>&& file, InodeIndex par
bool SyntheticFileSystem::removeFile(InodeIndex inode) bool SyntheticFileSystem::removeFile(InodeIndex inode)
{ {
ASSERT_INTERRUPTS_DISABLED();
auto it = m_inodes.find(inode); auto it = m_inodes.find(inode);
if (it == m_inodes.end()) if (it == m_inodes.end())
return false; return false;
@ -127,6 +129,7 @@ InodeIdentifier SyntheticFileSystem::rootInode() const
bool SyntheticFileSystem::enumerateDirectoryInode(InodeIdentifier inode, Function<bool(const DirectoryEntry&)> callback) const bool SyntheticFileSystem::enumerateDirectoryInode(InodeIdentifier inode, Function<bool(const DirectoryEntry&)> callback) const
{ {
InterruptDisabler disabler;
ASSERT(inode.fileSystemID() == id()); ASSERT(inode.fileSystemID() == id());
#ifdef SYNTHFS_DEBUG #ifdef SYNTHFS_DEBUG
kprintf("[synthfs] enumerateDirectoryInode %u\n", inode.index()); kprintf("[synthfs] enumerateDirectoryInode %u\n", inode.index());
@ -150,6 +153,7 @@ bool SyntheticFileSystem::enumerateDirectoryInode(InodeIdentifier inode, Functio
InodeMetadata SyntheticFileSystem::inodeMetadata(InodeIdentifier inode) const InodeMetadata SyntheticFileSystem::inodeMetadata(InodeIdentifier inode) const
{ {
InterruptDisabler disabler;
ASSERT(inode.fileSystemID() == id()); ASSERT(inode.fileSystemID() == id());
#ifdef SYNTHFS_DEBUG #ifdef SYNTHFS_DEBUG
kprintf("[synthfs] inodeMetadata(%u)\n", inode.index()); 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 Unix::ssize_t SyntheticFileSystem::readInodeBytes(InodeIdentifier inode, Unix::off_t offset, Unix::size_t count, byte* buffer) const
{ {
InterruptDisabler disabler;
ASSERT(inode.fileSystemID() == id()); ASSERT(inode.fileSystemID() == id());
#ifdef SYNTHFS_DEBUG #ifdef SYNTHFS_DEBUG
kprintf("[synthfs] readInode %u\n", inode.index()); kprintf("[synthfs] readInode %u\n", inode.index());