radare2/libr/trace/trace.c
pancake a89fabf552 * Major refactoring work done for r_trace
- Now build by default with the rest of libr
  - drop read_at dependency for r_trace
* Some stuff has been moved from r_util to r_types
  - max/min int values and so on
  - eprintf lives there now
2009-03-13 10:39:54 +00:00

315 lines
6.4 KiB
C

/* radare - LGPL - Copyright 2008-2009 pancake<nopcode.org> */
#include "r_trace.h"
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int r_trace_init(struct r_trace_t *t)
{
INIT_LIST_HEAD(&t->traces);
t->dup = 0;
t->tag = -1;
t->changed = 0;
t->num = 0;
t->printf = printf;
return R_TRUE;
}
struct r_trace_t *r_trace_new()
{
struct r_trace_t *tr = MALLOC_STRUCT(struct r_trace_t);
r_trace_init(tr);
return tr;
}
struct r_trace_t *r_r_trace_free(struct r_trace_t *tr)
{
r_trace_reset(tr);
free(&tr->traces);
free(tr);
return NULL;
}
int r_trace_tag_get(struct r_trace_t *t)
{
return t->tag;
}
int r_trace_tag_set(struct r_trace_t *t, int id)
{
if (id>=-1&&id<64) {
t->tag = id;
return 1;
}
return 0;
}
int r_trace_sort(struct r_trace_t *t)
{
struct list_head *pos, *pos2;
struct list_head *n, *n2;
int ch = R_FALSE;
if (t->changed)
list_for_each_safe(pos, n, &t->traces) {
struct r_trace_item_t *r =
list_entry(pos, struct r_trace_item_t, list);
list_for_each_safe(pos2, n2, &t->traces) {
struct r_trace_item_t *r2 =
list_entry(pos2, struct r_trace_item_t, list);
if ((r != r2) && (r->addr > r2->addr)) {
list_move(pos, pos2);
ch = R_TRUE;
}
}
}
return t->changed = ch;
}
struct r_trace_item_t *r_trace_get(struct r_trace_t *t, u64 addr, int tag)
{
struct list_head *pos;
list_for_each(pos, &t->traces) {
struct r_trace_item_t *h = list_entry(pos, struct r_trace_item_t, list);
if (tag != -1 && !(h->tags & (1<<tag)))
continue;
if (h->addr == addr)
return h;
}
return NULL;
}
// num of traces for an address
int r_trace_times(struct r_trace_t *tr, u64 addr)
{
struct r_trace_item_t *t = r_trace_get(tr, addr, tr->tag);
return t?t->times:0;
}
int r_trace_count(struct r_trace_t *tr, u64 addr)
{
struct r_trace_item_t *t = r_trace_get(tr, addr, tr->tag);
return t?t->count:0;
}
int r_trace_index(struct r_trace_t *tr, u64 addr)
{
int idx = -1;
struct list_head *pos;
list_for_each(pos, &tr->traces) {
struct r_trace_item_t *h = list_entry
(pos, struct r_trace_item_t, list);
idx++;
if (h->addr == addr)
return idx;
}
return idx;
}
int r_trace_set_times(struct r_trace_t *tr, u64 addr, int times)
{
struct r_trace_item_t *t;
struct list_head *pos;
/* update times counter */
list_for_each(pos, &tr->traces) {
t = list_entry(pos, struct r_trace_item_t, list);
if (t->addr == addr) {
t->times = times;
return 1;
}
}
return 0;
}
int r_trace_add(struct r_trace_t *tr, u64 addr, int opsize)
{
struct r_trace_item_t *t;
struct list_head *pos;
/* update times counter */
list_for_each(pos, &tr->traces) {
t = list_entry(pos, struct r_trace_item_t, list);
if (t->addr == addr) {
if (tr->dup) {
if (tr->tag != -1)
t->tags |= tr->tag;
++(t->times);
} else {
t->count = ++tr->num;
gettimeofday(&(t->tm), NULL);
if (tr->tag != -1)
t->tags |= tr->tag;
return ++(t->times);
}
}
}
t = MALLOC_STRUCT(struct r_trace_item_t);
memset(t,'\0',sizeof(struct r_trace_item_t));
t->addr = addr;
t->times = 1;
t->opsize = opsize;
gettimeofday(&(t->tm), NULL);
t->count = ++tr->num;
if (tr->tag != -1)
t->tags |= tr->tag;
tr->changed = 1;
list_add_tail(&(t->list), &tr->traces);
//eprintf("new trace (0x%08x)\n", (unsigned long)addr);
return t->times;
}
u64 r_trace_range(struct r_trace_t *t, u64 from, int tag)
{
struct r_trace_item_t *h;
u64 last = from;
u64 last2 = 0LL;
while(last != last2) {
last2 = last;
h = r_trace_get(t, last, tag);
if (h) {
if (tag != -1 && !(h->tags & (1<<tag)))
continue;
last = last + h->opsize;
}
}
return last;
}
u64 r_trace_next(struct r_trace_t *tr, u64 from, int tag)
{
u64 next = U64_MAX;
struct list_head *pos;
struct r_trace_item_t *h;
list_for_each(pos, &tr->traces) {
h = list_entry(pos, struct r_trace_item_t, list);
if (tag != -1 && !(h->tags & (1<<tag)))
continue;
if (h->addr > from && h->addr < next)
next = h->addr;
}
if (next == U64_MAX)
return U64_MIN;
return next;
}
#if 0
/* buggy version */
u64 trace_next(u64 from)
{
u64 next;
int next_init = 0;
struct list_head *pos;
struct trace_t *h;
list_for_each(pos, &traces) {
h = list_entry(pos, struct trace_t, list);
if (!next_init) {
if (h->addr > from && h->addr < next) {
next = h->addr;
next_init = 1;
}
continue;
}
if (h->addr > from && h->addr < next)
next = h->addr;
}
if (next_init == 0)
return NULL;
return next;
}
#endif
void r_trace_show(struct r_trace_t *tr, int plain, int tag)
{
u64 from = 0LL;
u64 last;
char opcode[64];
struct list_head *pos;
struct r_trace_item_t *h;
if (tag != -1)
eprintf("Displaying tag: %d\n", tag+1);
r_trace_sort(tr);
opcode[0]='\0';
/* get the lower address */
list_for_each(pos, &tr->traces) {
h = list_entry(pos, struct r_trace_item_t, list);
if (from == 0LL)
from = h->addr;
if (h->addr < from)
from = h->addr;
if (tag != -1 && !(h->tags & (1<<tag)))
continue;
switch(plain) {
case 1:
tr->printf("0x%08llx %d %d tags=%08llx\n",
h->addr, h->times, h->count, h->tags);
break;
case 2:
//config.verbose=0;
tr->printf("%03d %03d ", h->times, h->count);
sprintf(opcode, "pd 1 @ 0x%08llx", h->addr);
tr->printf(opcode); // XXX
// TODO: disassemble opcode here !!! WTF!
//radare_cmd_raw(opcode, 0);
//radare_read_at(h->addr, bytes, 32);
//udis_arch_string(config.arch, opcode, bytes, config.endian, h->addr, 32, 0);
break;
}
}
if (plain>0)
return;
while(from) {
last = r_trace_range(tr, from, tag);
if (last == from)
break;
// TODO: show timestamps
if (plain==0)
tr->printf("0x%08llx - 0x%08llx\n", from, last);
else tr->printf("ar+ 0x%08llx 0x%08llx\n", from, last);
from = r_trace_next(tr, last, tag);
}
}
void r_trace_reset(struct r_trace_t *tr)
{
struct list_head *pos;
struct r_trace_item_t *h;
list_for_each(pos, &tr->traces) {
h = list_entry(pos, struct r_trace_item_t, list);
free(h);
}
INIT_LIST_HEAD(&tr->traces);
}
int r_trace_get_between(struct r_trace_t *tr, u64 from, u64 to)
{
int ctr = 0;
struct list_head *pos;
struct r_trace_item_t *h;
/* get the lower address */
list_for_each(pos, &tr->traces) {
h = list_entry(pos, struct r_trace_item_t, list);
if (tr->tag != -1 && !(h->tags & (1<<tr->tag)))
continue;
if (h->addr >= from && h->addr <=to)
ctr++;
}
return ctr;
}