#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "archtrace.h" #pragma profile 0 /* * this is the wrong place for this, and a very large hammer, * but at least we are controlling access to kernel memory. * must match mmuinit() */static voidkmem(int write){ PTE x, *p; for(x = KTZERO; x < (ulong)etext; x += BY2PG){ p = mmuwalk(m->pdb, x, 2, 0); if(p == nil) panic("kmem"); if(write) *p |= PTEWRITE; else *p &= ~PTEWRITE; }} enum { CALL = 0xe8, JMP = 0xeb, RET = 0xc3, NOP = 0x90,}; char*archtracectlr(Archtrace *a, char *p, char *e){ int i; for(i = 0; i < a->nprobe; i++) p = seprint(p, e, "# tracept %c %#.8p\n", a->probe[i]==NOP? 'X': 'E', a->text[i]); return p;} voidarchtraceinstall(Archtrace *a){ int i; kmem(1); for(i = 0; i < a->nprobe; i++) *a->text[i] = a->probe[i]; kmem(0);} voidarchtraceuninstall(Archtrace *a){ int i; kmem(1); for(i = 0; i < a->nprobe; i++) *a->text[i] = a->orig[i]; kmem(0);} static intcall4(uchar *call, uchar *targ){ uchar buf[5]; ulong l; buf[0] = CALL; l = targ - (call + 5); buf[1] = l; buf[2] = l>>8; buf[3] = l>>16; buf[4] = l>>24; return memcmp(buf, call, 5);} static uchar startsig[] = {JMP, 0x05}; intmkarchtrace(Archtrace *a, uchar *start, uchar **endp){ uchar *p, *end; /* * search by signatures. we don't really * care we get a whole function or not. */ end = *endp; for(p = start; p + 6 <= end; p++) if(memcmp(p, startsig, sizeof startsig) == 0){ if(call4(p + 2, (uchar*)_tracein) == 0){ a->text[a->nprobe] = start + 1; a->orig[a->nprobe] = *a->text[a->nprobe]; a->probe[a->nprobe] = 0; /* jmp 2f */ a->nprobe++; } }else if(p[0] == RET && p[6] == RET){ if(call4(p + 1, (uchar*)_traceout) == 0){ if(a->nprobe == Maxprobe) error("too many exits"); a->text[a->nprobe] = p; a->orig[a->nprobe] = *a->text[a->nprobe]; a->probe[a->nprobe] = NOP; a->nprobe++; } }// *endp = a->text[a->nprobe - 1]; return 0;}
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "archtrace.h"
#pragma profile 0
/*
* this is the wrong place for this, and a very large hammer,
* but at least we are controlling access to kernel memory.
* must match mmuinit()
*/
static void
kmem(int write)
{
PTE x, *p;
for(x = KTZERO; x < (ulong)etext; x += BY2PG){
p = mmuwalk(m->pdb, x, 2, 0);
if(p == nil)
panic("kmem");
if(write)
*p |= PTEWRITE;
else
*p &= ~PTEWRITE;
}
}
enum {
CALL = 0xe8,
JMP = 0xeb,
RET = 0xc3,
NOP = 0x90,
};
char*
archtracectlr(Archtrace *a, char *p, char *e)
{
int i;
for(i = 0; i < a->nprobe; i++)
p = seprint(p, e, "# tracept %c %#.8p\n",
a->probe[i]==NOP? 'X': 'E', a->text[i]);
return p;
}
void
archtraceinstall(Archtrace *a)
{
int i;
kmem(1);
for(i = 0; i < a->nprobe; i++)
*a->text[i] = a->probe[i];
kmem(0);
}
void
archtraceuninstall(Archtrace *a)
{
int i;
kmem(1);
for(i = 0; i < a->nprobe; i++)
*a->text[i] = a->orig[i];
kmem(0);
}
static int
call4(uchar *call, uchar *targ)
{
uchar buf[5];
ulong l;
buf[0] = CALL;
l = targ - (call + 5);
buf[1] = l;
buf[2] = l>>8;
buf[3] = l>>16;
buf[4] = l>>24;
return memcmp(buf, call, 5);
}
static uchar startsig[] = {JMP, 0x05};
int
mkarchtrace(Archtrace *a, uchar *start, uchar **endp)
{
uchar *p, *end;
/*
* search by signatures. we don't really
* care we get a whole function or not.
*/
end = *endp;
for(p = start; p + 6 <= end; p++)
if(memcmp(p, startsig, sizeof startsig) == 0){
if(call4(p + 2, (uchar*)_tracein) == 0){
a->text[a->nprobe] = start + 1;
a->orig[a->nprobe] = *a->text[a->nprobe];
a->probe[a->nprobe] = 0; /* jmp 2f */
a->nprobe++;
}
}else if(p[0] == RET && p[6] == RET){
if(call4(p + 1, (uchar*)_traceout) == 0){
if(a->nprobe == Maxprobe)
error("too many exits");
a->text[a->nprobe] = p;
a->orig[a->nprobe] = *a->text[a->nprobe];
a->probe[a->nprobe] = NOP;
a->nprobe++;
}
}
// *endp = a->text[a->nprobe - 1];
return 0;
}