[kernel] Add debug names to processes

To make debugging easier, add names to processes. These are arbitrary
and supplied by the caller of process_create. The max is 31 characters
in debug configuration, and 0 in release.
This commit is contained in:
Justin C. Miller
2024-08-12 19:40:20 -07:00
parent ee24ec8d5c
commit d3c1d6cc34
8 changed files with 104 additions and 26 deletions

View File

@@ -12,7 +12,9 @@ object process : object {
]
# Create a new empty process
method create [constructor]
method create [constructor] {
param name string
}
# Stop all threads and exit the given process
method kill [destructor cap:kill]

View File

@@ -86,7 +86,7 @@ load_init_server(bootproto::program &program, uintptr_t modules_address)
using bootproto::section_flags;
using obj::vm_flags;
obj::process *p = new obj::process;
obj::process *p = new obj::process {"srv.init"};
j6_handle_t sys_handle =
g_cap_table.create(&obj::system::get(), obj::system::init_caps);

View File

@@ -1,3 +1,4 @@
#include <j6/memutils.h>
#include <util/no_construct.h>
#include "kassert.h"
@@ -18,10 +19,18 @@ obj::process &g_kernel_process = __g_kernel_process_storage.value;
namespace obj {
process::process() :
process::process(const char *name) :
kobject {kobject::type::process},
m_state {state::running}
{
if constexpr(__use_process_names) {
memset(m_name, 0, sizeof(m_name));
if (name) {
static constexpr size_t charlen = sizeof(m_name) - 1;
for (size_t i = 0; i < charlen && name[i]; ++i)
m_name[i] = name[i];
}
}
}
// The "kernel process"-only constructor
@@ -30,6 +39,11 @@ process::process(page_table *kpml4) :
m_space {kpml4},
m_state {state::running}
{
if constexpr(__use_process_names) {
static constexpr char kernel[] = "KERNEL";
memcpy(m_name, kernel, sizeof(kernel));
memset(m_name + sizeof(kernel), 0, sizeof(m_name) - sizeof(kernel));
}
}
process::~process()

View File

@@ -13,6 +13,14 @@
namespace obj {
static constexpr bool __use_process_names =
#ifdef __jsix_config_debug
true;
#else
false;
#endif
class process :
public kobject
{
@@ -32,7 +40,7 @@ public:
static constexpr kobject::type type = kobject::type::process;
/// Constructor.
process();
process(const char *name);
/// Destructor.
virtual ~process();
@@ -47,6 +55,9 @@ public:
/// Get the process' virtual memory space
vm_space & space() { return m_space; }
/// Get the debugging name of the process
const char *name() { if constexpr(__use_process_names) return m_name; else return nullptr; }
/// Create a new thread in this process
/// \args rsp3 If non-zero, sets the ring3 stack pointer to this value
/// \args priority The new thread's scheduling priority
@@ -107,6 +118,15 @@ private:
enum class state : uint8_t { running, exited };
state m_state;
static constexpr size_t max_name_len =
#ifdef __jsix_config_debug
32;
#else
0;
#endif
char m_name[max_name_len];
};
} // namespace obj

View File

@@ -2,6 +2,7 @@
#include "cpu.h"
#include "display.h"
#include "kernel.dir/memory.h"
#include "objects/process.h"
#include "objects/thread.h"
#include "serial.h"
@@ -9,6 +10,44 @@
namespace panicking {
template <typename T> inline bool
check_pointer(T p)
{
static constexpr uint64_t large_flag = (1<<7);
static constexpr uint64_t pointer_mask = 0x0000fffffffff000;
static constexpr uintptr_t canon_mask = 0xffff800000000000;
uintptr_t addr = reinterpret_cast<uintptr_t>(p);
uintptr_t canon_bits = addr & canon_mask;
if (canon_bits && canon_bits != canon_mask)
return false;
uintptr_t pml4 = 0;
asm volatile ( "mov %%cr3, %0" : "=r" (pml4) );
pml4 += mem::linear_offset;
uint64_t *table = reinterpret_cast<uint64_t*>(pml4);
unsigned shift = 39;
while (table) {
unsigned index = (addr >> shift) & 0x1ffull;
uint64_t entry = table[index];
if ((entry & 0x1) == 0)
return false;
if ((entry & large_flag) || shift <= 12)
return true;
uint64_t next = (entry & pointer_mask) + mem::linear_offset;
table = reinterpret_cast<uint64_t*>(next);
shift -= 9;
}
return false;
}
const char *clear = "\e[0m\n";
void
@@ -40,23 +79,17 @@ print_cpu(serial_port &out, cpu_data &cpu)
{
uint32_t process = cpu.process ? cpu.process->obj_id() : 0;
uint32_t thread = cpu.thread ? cpu.thread->obj_id() : 0;
const char *name = cpu.process ? cpu.process->name() : "<Unknown>";
out.write("\n \e[0;31m==[ CPU: ");
char buffer[64];
util::format({buffer, sizeof(buffer)}, "%4d <%02lx:%02lx>",
cpu.id + 1, process, thread);
size_t len = util::format({buffer, sizeof(buffer)}, "%4d <%02lx:%02lx> ]: %s ",
cpu.id + 1, process, thread, name);
out.write(buffer);
out.write(" ]=============================================================\n");
}
template <typename T> inline bool
canonical(T p)
{
static constexpr uintptr_t mask = 0xffff800000000000;
uintptr_t addr = reinterpret_cast<uintptr_t>(p);
return (addr & mask) == mask || (addr & mask) == 0;
for (size_t i = 0; i < (74-len); ++i) out.write("=");
out.write("\n");
}
void
@@ -65,18 +98,26 @@ print_callstack(serial_port &out, symbol_table &syms, frame const *fp)
char message[512];
unsigned count = 0;
while (canonical(fp) && fp && fp->return_addr) {
char const *name = syms.find_symbol(fp->return_addr);
while (fp && check_pointer(fp)) {
const uintptr_t ret = fp->return_addr;
char const *name = ret ? syms.find_symbol(ret) : "<END>";
if (!name)
name = canonical(fp->return_addr) ? "<unknown>" : "<corrupt>";
name = check_pointer(fp->return_addr) ? "<unknown>" : "<unmapped>";
util::format({message, sizeof(message)},
" \e[0;33mframe %2d: <0x%016lx> \e[1;33m%s\n",
count++, fp->return_addr, name);
" \e[0;33mframe %2d: <0x%016lx> <0x%016lx> \e[1;33m%s\n",
count++, fp, fp->return_addr, name);
out.write(message);
if (!ret) return;
fp = fp->prev;
}
const char *result = fp ? " <inaccessible>" : "";
util::format({message, sizeof(message)}, " \e[0mfinal <0x%016lx>%s\n",
fp, result);
out.write(message);
}
static void

View File

@@ -10,9 +10,9 @@ using namespace obj;
namespace syscalls {
j6_status_t
process_create(j6_handle_t *self)
process_create(j6_handle_t *self, const char *path)
{
process *p = construct_handle<process>(self);
process *p = construct_handle<process>(self, path);
log::info(logs::task, "Process <%02lx> created", p->obj_id());
return j6_status_ok;
}

View File

@@ -23,9 +23,10 @@ using system = class ::system;
j6_status_t
log(uint8_t area, uint8_t severity, const char *message)
{
const char *name = process::current().name();
thread &th = thread::current();
log::log(static_cast<logs>(area), static_cast<log::level>(severity),
"<%02lx:%02lx>: %s", th.parent().obj_id(), th.obj_id(), message);
"<%02lx:%02lx> %s: %s", th.parent().obj_id(), th.obj_id(), name, message);
return j6_status_ok;
}

View File

@@ -192,10 +192,10 @@ give_handle(j6_handle_t proc, j6_handle_t h, const char *name)
}
static j6_handle_t
create_process(j6_handle_t sys, j6_handle_t slp, j6_handle_t vfs)
create_process(j6_handle_t sys, j6_handle_t slp, j6_handle_t vfs, const char *path)
{
j6_handle_t proc = j6_handle_invalid;
j6_status_t res = j6_process_create(&proc);
j6_status_t res = j6_process_create(&proc, path);
if (res != j6_status_ok) {
j6::syslog(j6::logs::srv, j6::log_level::error, "error loading program: creating process: %lx", res);
return j6_handle_invalid;
@@ -231,7 +231,7 @@ load_program(
const module *arg)
{
j6::syslog(j6::logs::srv, j6::log_level::info, "Loading program '%s' into new process", path);
j6_handle_t proc = create_process(sys, slp, vfs);
j6_handle_t proc = create_process(sys, slp, vfs, path);
if (proc == j6_handle_invalid)
return false;