#include <sys/systm.h>
#include <sys/sdt.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <machine/md_var.h>
#include <machine/vmparam.h>
#define SDT_PATCH_SIZE 5
bool
sdt_tracepoint_valid(uintptr_t patchpoint, uintptr_t target)
{
#ifdef __amd64__
if (patchpoint < KERNSTART || target < KERNSTART)
return (false);
#endif
if (patchpoint == target ||
patchpoint + SDT_PATCH_SIZE < patchpoint)
return (false);
#ifdef __amd64__
int64_t offset = target - (patchpoint + SDT_PATCH_SIZE);
if (offset < -(1l << 31) || offset > (1l << 31))
return (false);
#endif
return (true);
}
void
sdt_tracepoint_patch(uintptr_t patchpoint, uintptr_t target)
{
uint8_t instr[SDT_PATCH_SIZE];
int32_t disp;
bool old_wp;
KASSERT(sdt_tracepoint_valid(patchpoint, target),
("%s: invalid tracepoint %#jx -> %#jx",
__func__, (uintmax_t)patchpoint, (uintmax_t)target));
instr[0] = 0xe9;
disp = target - (patchpoint + SDT_PATCH_SIZE);
memcpy(&instr[1], &disp, sizeof(disp));
old_wp = disable_wp();
memcpy((void *)patchpoint, instr, sizeof(instr));
restore_wp(old_wp);
}
void
sdt_tracepoint_restore(uintptr_t patchpoint)
{
uint8_t instr[SDT_PATCH_SIZE];
bool old_wp;
#ifdef __amd64__
KASSERT(patchpoint >= KERNSTART,
("%s: invalid patchpoint %#lx", __func__, patchpoint));
#endif
for (int i = 0; i < SDT_PATCH_SIZE; i++)
instr[i] = 0x90;
old_wp = disable_wp();
memcpy((void *)patchpoint, instr, sizeof(instr));
restore_wp(old_wp);
}