mirror of
https://github.com/zer0condition/GoodmansKernel/
synced 2026-08-19 01:14:35 +00:00
138 lines
4.2 KiB
C
138 lines
4.2 KiB
C
/* trace_ring.c - per-import call trace for wasm guest debugging.
|
|
* ring buffer holds recent host-import invocations, export calls, and traps.
|
|
* GUI polls via ioctl for live view.
|
|
*/
|
|
#include "inc/gvm.h"
|
|
#include "../shared/goodmans_ioctl.h"
|
|
|
|
static gvm_trace_entry g_ring[GVM_TRACE_ENTRIES];
|
|
static ULONG64 g_seq = 0;
|
|
static ULONG g_head = 0;
|
|
static KSPIN_LOCK g_lock;
|
|
static BOOLEAN g_init = FALSE;
|
|
static volatile LONG g_mode = GVM_TRACE_OFF;
|
|
static volatile LONG g_only = 0; // module_id filter when mode==ON_MODULE
|
|
|
|
void
|
|
gvm_trace_init(void)
|
|
{
|
|
if (g_init) return;
|
|
RtlZeroMemory(g_ring, sizeof(g_ring));
|
|
KeInitializeSpinLock(&g_lock);
|
|
g_init = TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
gvm_trace_enabled_for(unsigned int module_id)
|
|
{
|
|
LONG m = g_mode;
|
|
if (m == GVM_TRACE_OFF) return FALSE;
|
|
if (m == GVM_TRACE_ON_ALL) return TRUE;
|
|
return (LONG)module_id == g_only;
|
|
}
|
|
|
|
void
|
|
gvm_trace_push(unsigned int module_id, unsigned int kind, const char* name,
|
|
unsigned int argc, const ULONG64* argv, ULONG64 rv)
|
|
{
|
|
if (!g_init) return;
|
|
if (!gvm_trace_enabled_for(module_id)) return;
|
|
|
|
LARGE_INTEGER now;
|
|
KeQuerySystemTimePrecise(&now);
|
|
|
|
// capture pre-lock so lock IRQL doesn't confuse the value
|
|
unsigned int cap_irql = (unsigned int)KeGetCurrentIrql();
|
|
unsigned int cap_tid = (unsigned int)(ULONG_PTR)PsGetCurrentThreadId();
|
|
|
|
KIRQL irql;
|
|
KeAcquireSpinLock(&g_lock, &irql);
|
|
gvm_trace_entry* e = &g_ring[g_head];
|
|
RtlZeroMemory(e, sizeof(*e));
|
|
e->timestamp_100ns = (ULONG64)now.QuadPart;
|
|
e->module_id = module_id;
|
|
e->kind = kind;
|
|
e->thread_id = cap_tid;
|
|
e->irql = cap_irql;
|
|
e->argc = argc > 4 ? 4 : argc;
|
|
for (unsigned int i = 0; i < e->argc; i++) e->argv[i] = argv[i];
|
|
e->rv = rv;
|
|
if (name) RtlStringCbCopyA(e->name, sizeof(e->name), name);
|
|
g_seq++;
|
|
g_head = (g_head + 1) % GVM_TRACE_ENTRIES;
|
|
KeReleaseSpinLock(&g_lock, irql);
|
|
}
|
|
|
|
NTSTATUS
|
|
gvm_ioctl_tail_trace(PIRP irp, PIO_STACK_LOCATION sp)
|
|
{
|
|
ULONG in_len = sp->Parameters.DeviceIoControl.InputBufferLength;
|
|
ULONG out_len = sp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
void* buf = irp->AssociatedIrp.SystemBuffer;
|
|
|
|
if (in_len < sizeof(gvm_trace_in) || out_len < sizeof(gvm_trace_out) || !buf) {
|
|
irp->IoStatus.Information = 0;
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
gvm_trace_in in;
|
|
RtlCopyMemory(&in, buf, sizeof(in));
|
|
|
|
gvm_trace_out* out = (gvm_trace_out*)ExAllocatePoolWithTag(
|
|
NonPagedPoolNx, sizeof(gvm_trace_out), 'gTrc');
|
|
if (!out) return STATUS_INSUFFICIENT_RESOURCES;
|
|
RtlZeroMemory(out, sizeof(*out));
|
|
|
|
KIRQL irql;
|
|
KeAcquireSpinLock(&g_lock, &irql);
|
|
|
|
ULONG64 seq_here = g_seq;
|
|
ULONG64 want_from = in.last_seq;
|
|
ULONG64 available = 0;
|
|
ULONG64 dropped = 0;
|
|
|
|
if (seq_here > want_from) {
|
|
available = seq_here - want_from;
|
|
if (available > GVM_TRACE_ENTRIES) {
|
|
dropped = available - GVM_TRACE_ENTRIES;
|
|
available = GVM_TRACE_ENTRIES;
|
|
}
|
|
ULONG start = (g_head + GVM_TRACE_ENTRIES - (ULONG)available) % GVM_TRACE_ENTRIES;
|
|
for (ULONG64 i = 0; i < available; i++) {
|
|
ULONG src = (start + (ULONG)i) % GVM_TRACE_ENTRIES;
|
|
out->entries[i] = g_ring[src];
|
|
}
|
|
}
|
|
out->next_seq = seq_here;
|
|
out->count = (unsigned int)available;
|
|
out->dropped = (unsigned int)dropped;
|
|
|
|
KeReleaseSpinLock(&g_lock, irql);
|
|
|
|
RtlCopyMemory(buf, out, sizeof(*out));
|
|
ExFreePoolWithTag(out, 'gTrc');
|
|
irp->IoStatus.Information = sizeof(gvm_trace_out);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
gvm_ioctl_trace_ctl(PIRP irp, PIO_STACK_LOCATION sp)
|
|
{
|
|
ULONG in_len = sp->Parameters.DeviceIoControl.InputBufferLength;
|
|
void* buf = irp->AssociatedIrp.SystemBuffer;
|
|
|
|
if (in_len < sizeof(gvm_trace_ctl_in) || !buf) {
|
|
irp->IoStatus.Information = 0;
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
gvm_trace_ctl_in in;
|
|
RtlCopyMemory(&in, buf, sizeof(in));
|
|
|
|
InterlockedExchange(&g_mode, (LONG)in.mode);
|
|
InterlockedExchange(&g_only, (LONG)in.module_id);
|
|
|
|
gvm_log_push("trace mode=%u module=%u", in.mode, in.module_id);
|
|
irp->IoStatus.Information = 0;
|
|
return STATUS_SUCCESS;
|
|
}
|