* Initial pseudo-working implementation of r_var API

- Remove temporal code
This commit is contained in:
pancake 2009-02-13 15:25:15 -08:00
parent 7b96c49110
commit 0c34c746bf
7 changed files with 376 additions and 1512 deletions

70
libr/include/r_var.h Normal file
View file

@ -0,0 +1,70 @@
#include "r_types.h"
#include "list.h"
#define R_VAR_ANAL_MAX 256
enum {
R_VAR_TYPE_NONE = 0,
R_VAR_TYPE_GLOBAL,
R_VAR_TYPE_LOCAL,
R_VAR_TYPE_ARG,
R_VAR_TYPE_ARGREG
};
struct r_var_anal_t {
int type;
int delta;
int count;
};
struct r_var_type_t {
char name[128];
char fmt[128];
unsigned int size;
struct list_head list;
};
struct r_var_t {
int anal_size;
struct r_var_anal_t anal[R_VAR_ANAL_MAX];
struct list_head vartypes;
struct list_head vars;
};
struct r_var_access_t {
u64 addr;
int set;
struct list_head list;
};
struct r_var_item_t {
int type; /* global, local... */
u64 addr; /* address where it is used */
u64 eaddr; /* address where it is used */
int delta; /* */
int arraysize; /* size of array var in bytes , 0 is no-array */
char name[128];
char vartype[128];
struct list_head access; /* list of accesses for this var */
struct list_head list;
};
/* api */
struct r_var_t *r_var_new();
void r_var_free(struct r_var_t *var);
int r_var_init(struct r_var_t *var);
int r_var_type_add(struct r_var_t *var, const char *typename, int size, const char *fmt);
int r_var_type_del(struct r_var_t *var, const char *typename);
int r_var_type_list(struct r_var_t *var);
const char *r_var_type_get(struct r_var_t *var, const char *datatype);
const char *r_var_type_to_string(int type);
/* food */
int r_var_item_print(struct r_var_t *var, struct r_var_item_t * v);
int r_var_list_show(struct r_var_t *var, u64 addr);
int r_var_list(struct r_var_t *var, u64 addr, int delta);
/* analyze */
int r_var_anal_get(struct r_var_t *var, int type);
void r_var_anal_reset(struct r_var_t *var);
int r_var_anal_add(struct r_var_t *var, int type, int delta);

5
libr/var/Makefile Normal file
View file

@ -0,0 +1,5 @@
NAME=r_var
OBJ=var.o
DEPS=r_util r_cons
include ../rules.mk

View file

@ -1,9 +1,2 @@
r_vars_add()
...
Contains old:
vars.c
data.c
analyze.c - related code var analysis (after analyze a function
return a list of accesses to local and lgobal vars)
See tmp/ fmi
API for accessing and analyzing variables

File diff suppressed because it is too large Load diff

View file

@ -1,143 +0,0 @@
/*
* Copyright (C) 2008
* pancake <youterm.com>
*
* radare is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* radare is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with radare; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "main.h"
#include "code.h"
#include "data.h"
#include "undo.h"
#include "flags.h"
#include "arch/csr/dis.h"
#include "arch/arm/disarm.h"
#include "arch/ppc/ppc_disasm.h"
#include "arch/m68k/m68k_disasm.h"
#include "arch/x86/udis86/types.h"
#include "arch/x86/udis86/extern.h"
#include "list.h"
struct reflines_t *reflines = NULL;
static struct list_head vartypes;
/* variables */
void data_comment_init(int new)
{
INIT_LIST_HEAD(&(vartypes));
}
int data_var_type_add(const char *typename, int size, const char *fmt)
{
struct var_type_t *d = (struct var_type_t *)
malloc(sizeof(struct var_type_t));
strncpy(d->name, typename, sizeof(d->name));
strncpy(d->fmt, fmt, sizeof(d->fmt));
d->size = size;
list_add(&(d->list), &vartypes);
return 0;
}
int data_var_type_del(const char *typename)
{
struct list_head *pos;
u64 ret = 0;
if (*typename==' ')typename=typename+1;
list_for_each(pos, &vartypes) {
struct var_type_t *d = (struct var_type_t *)list_entry(pos, struct var_type_t, list);
if (!strcmp(typename, d->name)) {
list_del(&(d->list));
return 1;
}
}
return 0;
}
int data_var_type_list()
{
struct list_head *pos;
u64 ret = 0;
list_for_each(pos, &vartypes) {
struct var_type_t *d = (struct var_type_t *)list_entry(pos, struct var_type_t, list);
cons_printf("%s %d %s\n", d->name, d->size, d->fmt);
}
return ret;
}
const char *data_var_type_get(const char *datatype)
{
struct list_head *pos;
u64 ret = 0;
list_for_each(pos, &vartypes) {
struct var_type_t *d = (struct var_type_t *)list_entry(pos, struct var_type_t, list);
//eprintf("---(%s)(%s)\n", d->name, datatype);
if (!strcmp(datatype, d->name))
return d;
}
return NULL;
}
int data_var_help()
{
cons_printf(
"Usage: Cv [name] [size] [pm-format-string]\n"
" Cv int 4 d ; define 'int' type\n"
" Cv- int ; remove 'int' var type\n"
" Cv float 4 f\n");
return 0;
}
int data_var_cmd(const char *str)
{
int len;
char *vstr;
char *arg, *arg2;
STRALLOC(vstr, str, len);
if (*str==' ')str=str+1;
switch(*str) {
case '?':
return data_var_help();
case '\0':
/* list var types */
data_var_type_list();
break;
case '-':
data_var_type_del(str+1);
break;
default:
arg = strchr(str, ' ');
if (arg==NULL)
return data_var_help();
*arg='\0'; arg=arg+1;
arg2 = strchr(arg, ' ');
if (arg2==NULL)
return data_var_help();
*arg2='\0'; arg2=arg2+1;
data_var_type_add(str, atoi(arg), arg2);
break;
}
return 0;
}

View file

@ -1,311 +0,0 @@
/* Copyleft 2009 - pancake<AT>youterm.com */
#include "main.h"
#include "list.h"
int var_add(u64 addr, u64 eaddr, int delta, int type, const char *vartype, const char *name, int arraysize);
// this can be nested inside the function_t which is not defined..
#if 0
struct function_t {
char name[128];
int framesize;
struct list_head ranges;
struct list_head vars;
};
#endif
static struct list_head vars;
/* variable types */
enum {
VAR_T_GLOBAL,
VAR_T_LOCAL,
VAR_T_ARG,
VAR_T_ARGREG
};
struct var_xs_t {
u64 addr;
int set;
struct list_head list;
};
struct var_t {
int type; /* global, local... */
u64 addr; /* address where it is used */
u64 eaddr; /* address where it is used */
int delta; /* */
int arraysize; /* size of array var in bytes , 0 is no-array */
char name[128];
char vartype[128];
struct list_head access; /* list of accesses for this var */
struct list_head list;
};
int var_add(u64 addr, u64 eaddr, int delta, int type, const char *vartype, const char *name, int arraysize)
{
struct var_t *var = (struct var_t *)malloc(sizeof(struct var_t));
/* TODO: check of delta inside funframe */
if (strchr(name, ' ') || strchr(vartype,' ')) {
eprintf("Invalid name/type\n");
return 0;
}
strncpy(var->name, name, sizeof(var->name));
strncpy(var->vartype, vartype, sizeof(var->vartype));
var->delta = delta;
var->type = type;
var->addr = addr;
var->eaddr = eaddr;
var->arraysize = arraysize;
INIT_LIST_HEAD(&(var->access));
list_add(&(var->list), &vars);
return 1;
}
int var_add_access(u64 addr, int delta, int type, int set)
{
struct list_head *pos;
struct var_t *v;
int reloop = 0;
_reloop:
list_for_each(pos, &vars) {
v = (struct var_t *)list_entry(pos, struct var_t, list);
if (addr >= v->addr) {
//if (!strcmp(name, v->name)) {
if (delta == v->delta && type == v->type) {
struct var_xs_t *xs = (struct var_xs_t *)malloc(sizeof(struct var_xs_t));
xs->addr = addr;
xs->set = set;
//eprintf("==> %llx\n", addr);
/* add var access here */
list_add(&(xs->list), &(v->access));
return 1;
}
}
}
/* automatic init */
/* detect function in CF list */
{
u64 from = 0LL, to = 0LL;
if ( data_get_fun_for(addr, &from, &to) ) {
char varname[32];
if (delta < 0) {
delta = -delta;
sprintf(varname, "arg_%d", delta);
} else sprintf(varname, "var_%d", delta);
//eprintf("0x%08llx: NEW LOCAL VAR %d\n", from, delta);
var_add(from, to, delta, VAR_T_LOCAL, "int32", varname, 1);
if (reloop) {
#warning THIS IS BUGGY: SHOULD NEVER HAPPEN
eprintf("LOOPING AT 0x%08llx NOT ADDING AN ACCESS\n", addr);
return 0;
}
reloop=1;
goto _reloop;
return var_add_access(addr, delta, type, set);
} else eprintf("Cannot find bounding function at 0x%08llx\n", addr);
}
return 0;
}
const char *var_type_str(int fd)
{
switch(fd) {
case VAR_T_GLOBAL: return "global";
case VAR_T_LOCAL: return "local";
case VAR_T_ARG: return "arg";
case VAR_T_ARGREG: return "fastarg";
}
return "(?)";
}
u32 var_dbg_read(int delta)
{
/* XXX: EBP ONLY FOR X86 */
u32 ret;
u64 foo = get_offset("ebp");
foo-=delta;
radare_read_at(foo, (u8*)&ret, 4);
return ret;
}
void print_mem(u64 addr, const u8 *buf, u64 len, const char *fmt, int endian);
int var_print_value(struct var_t *v)
{
struct var_type_t *t = data_var_type_get(v->vartype);
if (t == NULL) {
u32 value = var_dbg_read(v->delta);
// TODO: use var type to
cons_printf("%x", value);
} else {
u8 buf[1024];
int verbose = config.verbose;
int size = v->arraysize * t->size;
u64 foo = get_offset("ebp");
foo -= v->delta;
radare_read_at(foo, buf, size);
//eprintf("PRINT_MEM(%llx,%d,%s)\n", foo, size, t->fmt);
config.verbose = 0;
print_mem(foo, buf, size, t->fmt, config.endian);
config.verbose = verbose;
}
return 0;
}
/* CFV */
int var_list_show(u64 addr)
{
char buf[256];
struct list_head *pos, *pos2;
struct var_t *v;
struct var_xs_t *x;
list_for_each(pos, &vars) {
v = (struct var_t *)list_entry(pos, struct var_t, list);
if (addr == 0 || (addr >= v->addr && addr <= v->eaddr)) {
u32 value = var_dbg_read(v->delta);
if (v->arraysize>1)
cons_printf("%s %s %s[%d] = ", var_type_str(v->type), v->vartype, v->arraysize, v->name);
else cons_printf("%s %s %s = ", var_type_str(v->type), v->vartype, v->name);
var_print_value(v);
/* TODO: detect pointer to strings and so on */
if (string_flag_offset(buf, value, 0))
cons_printf(" ; points to: %s\n", buf);
else cons_newline();
}
}
return 0;
}
/* 0,0 to list all */
int var_list(u64 addr, int delta)
{
struct list_head *pos, *pos2;
struct var_t *v;
struct var_xs_t *x;
list_for_each(pos, &vars) {
v = (struct var_t *)list_entry(pos, struct var_t, list);
if (addr == 0 || (addr >= v->addr && addr <= v->eaddr)) {
cons_printf("0x%08llx - 0x%08llx type=%s type=%s name=%s delta=%d array=%d\n",
v->addr, v->eaddr, var_type_str(v->type),
v->vartype, v->name, v->delta, v->arraysize);
list_for_each_prev(pos2, &v->access) {
x = (struct var_xs_t *)list_entry(pos2, struct var_xs_t, list);
cons_printf(" 0x%08llx %s\n", x->addr, x->set?"set":"get");
}
}
}
return 0;
}
int var_init()
{
INIT_LIST_HEAD(&vars);
data_var_type_add("char", 1, "b");
data_var_type_add("byte", 1, "b");
data_var_type_add("int", 4, "d");
data_var_type_add("int32", 4, "d");
data_var_type_add("dword", 4, "x");
data_var_type_add("float", 4, "f");
}
int var_help()
{
eprintf("Try Cv?\n");
eprintf(" Cv 12 int buffer[3]\n");
eprintf(" Cv 12 byte buffer[1024]\n");
}
int var_cmd_help()
{
eprintf("Try CF[aAv][gs] [delta]\n");
eprintf(" CFag 0 = arg0 get\n");
eprintf(" CFvs 12 = var12 set\n");
eprintf("a = arg, A = fastarg, v = var\n");
}
int var_cmd(const char *str)
{
char *p,*p2,*p3;
int type, delta, len = strlen(str)+1;
p = alloca(len);
memcpy(p, str, len);
str = p;
switch(*str) {
case 'V': // show vars in human readable format
return var_list_show(config.seek);
case 'v': // frame variable
case 'a': // stack arg
case 'A': // fastcall arg
// XXX nested dup
switch(*str) {
case 'v': type = VAR_T_LOCAL; break;
case 'a': type = VAR_T_ARG; break;
case 'A': type = VAR_T_ARGREG; break;
}
/* Variable access CFvs = set fun var */
switch(str[1]) {
case '\0': return var_list(0, 0);
case '.': return var_list(config.seek, 0);
case 's': return var_add_access(config.seek, atoi(str+2), type, 1);
case 'g': return var_add_access(config.seek, atoi(str+2), type, 0);
}
str = str+1;
if (str[0]==' ')str=str+1;
delta = atoi(str);
p = strchr(str, ' ');
if (p==NULL)
return var_cmd_help();
p[0]='\0'; p=p+1;
p2 = strchr(p, ' ');
if (p2==NULL)
return var_help();
p2[0]='\0'; p2=p2+1;
p3 = strchr(p2,'[');
if (p3 != NULL) {
p3[0]='\0';
p3=p3+1;
}
var_add(config.seek, config.seek, delta, type, p, p2, p3?atoi(p3):0);
break;
default:
var_help();
break;
}
return 0;
}
#if 0
-- function boundaries are used to limit variables life-cycle --
// global vars are handled as flags??
// "CV 0x8049200 x global_counter
// local vars
// types: glar: g=global, l=local, a=arg, r=argreg
Cv l d i @ 0x8048200
/* using code analysis we can identify local var accesses */
f.ex:
; Set var0
0x4a13c014, mov [ebp-0x34], eax
; set name for variable accessed.
Cvn counter @ 0x4a13c014
stack frame {
var1 { offset, size, type, name }
var2 { offset, size, type, name }
}
// how to track a variable
#endif

300
libr/var/var.c Normal file
View file

@ -0,0 +1,300 @@
/* radare - LGPL - Copyright 2008-2009 pancake<nopcode.org> */
#include "r_var.h"
#include "r_cons.h"
struct r_var_t *r_var_new()
{
struct r_var_t *var = MALLOC_STRUCT(struct r_var_t);
r_var_init(var);
return var;
}
void r_var_free(struct r_var_t *var)
{
free(var);
}
int r_var_init(struct r_var_t *var)
{
INIT_LIST_HEAD(&(var->vartypes));
INIT_LIST_HEAD(&(var->vars));
r_var_type_add(var, "char", 1, "b");
r_var_type_add(var, "byte", 1, "b");
r_var_type_add(var, "int", 4, "d");
r_var_type_add(var, "int32", 4, "d");
r_var_type_add(var, "dword", 4, "x");
r_var_type_add(var, "float", 4, "f");
r_var_anal_reset(var);
return R_TRUE;
}
/* data.c */
int r_var_type_add(struct r_var_t *var, const char *typename, int size, const char *fmt)
{
struct r_var_type_t *d = (struct r_var_type_t *)
malloc(sizeof(struct r_var_type_t));
strncpy(d->name, typename, sizeof(d->name));
strncpy(d->fmt, fmt, sizeof(d->fmt));
d->size = size;
list_add(&(d->list), &var->vartypes);
return R_TRUE;
}
int r_var_type_del(struct r_var_t *var, const char *typename)
{
struct list_head *pos;
if (*typename==' ') typename = typename+1;
list_for_each(pos, &var->vartypes) {
struct r_var_type_t *d = (struct r_var_type_t *)
list_entry(pos, struct r_var_type_t, list);
if (!strcmp(typename, d->name)) {
list_del(&(d->list));
return 1;
}
}
return 0;
}
int r_var_type_list(struct r_var_t *var)
{
struct list_head *pos;
u64 ret = 0;
list_for_each(pos, &var->vartypes) {
struct r_var_type_t *d = (struct r_var_type_t *)
list_entry(pos, struct r_var_type_t, list);
cons_printf("%s %d %s\n", d->name, d->size, d->fmt);
}
return ret;
}
struct r_var_type_d *r_var_type_get(struct r_var_t *var, const char *datatype)
{
struct list_head *pos;
list_for_each(pos, &var->vartypes) {
struct r_var_type_t *d = (struct r_var_type_t *)
list_entry(pos, struct r_var_type_t, list);
//eprintf("---(%s)(%s)\n", d->name, datatype);
if (!strcmp(datatype, d->name))
return d;
}
return NULL;
}
/* vars.c */
int r_var_add(struct r_var_t *v, u64 addr, u64 eaddr, int delta, int type, const char *vartype, const char *name, int arraysize)
{
struct r_var_item_t *var = MALLOC_STRUCT(struct r_var_item_t);
/* TODO: check of delta inside funframe */
if (strchr(name, ' ') || strchr(vartype,' ')) {
fprintf(stderr, "r_var_add: Invalid name/type\n");
return 0;
}
strncpy(var->name, name, sizeof(var->name));
strncpy(var->vartype, vartype, sizeof(var->vartype));
var->delta = delta;
var->type = type;
var->addr = addr;
var->eaddr = eaddr;
var->arraysize = arraysize;
INIT_LIST_HEAD(&(var->access));
list_add(&(var->list), &v->vars);
return 1;
}
int r_var_add_access(struct r_var_t *var, u64 addr, int delta, int type, int set)
{
u64 from = 0LL, to = 0LL;
struct list_head *pos;
struct r_var_item_t *v;
int reloop = 0;
_reloop:
list_for_each(pos, &var->vars) {
v = (struct r_var_item_t*)list_entry(pos, struct r_var_item_t, list);
if (addr >= v->addr) {
//if (!strcmp(name, v->name)) {
if (delta == v->delta && type == v->type) {
struct r_var_access_t *xs = MALLOC_STRUCT(struct r_var_access_t);
xs->addr = addr;
xs->set = set;
/* add var access here */
list_add(&(xs->list), &(v->access));
return 1;
}
}
}
/* automatic init */
/* detect function in CF list */
from = to = 0LL;
// XXX THIS IS FOR R_META?
if ( data_get_fun_for(addr, &from, &to) ) {
char varname[32];
if (delta < 0) {
delta = -delta;
sprintf(varname, "arg_%d", delta);
} else sprintf(varname, "var_%d", delta);
//eprintf("0x%08llx: NEW LOCAL VAR %d\n", from, delta);
r_var_add(var, from, to, delta, R_VAR_TYPE_LOCAL, "int32", varname, 1);
if (reloop) {
#warning THIS IS BUGGY: SHOULD NEVER HAPPEN
fprintf(stderr, "LOOPING AT 0x%08llx NOT ADDING AN ACCESS\n", addr);
return 0;
}
reloop=1;
goto _reloop;
return r_var_add_access(var, addr, delta, type, set);
} else fprintf(stderr, "Cannot find bounding function at 0x%08llx\n", addr);
return 0;
}
/* XXX: this is a static method..no need for $self argument */
const char *r_var_type_to_string(int type)
{
switch(type) {
case R_VAR_TYPE_GLOBAL: return "global";
case R_VAR_TYPE_LOCAL: return "local";
case R_VAR_TYPE_ARG: return "arg";
case R_VAR_TYPE_ARGREG: return "fastarg";
}
return "(?)";
}
#if 0
/* This stuff belongs to the plugins realm */
u32 var_dbg_read(int delta)
{
/* XXX: EBP ONLY FOR X86 */
u32 ret;
u64 foo = get_offset("ebp");
foo-=delta;
radare_read_at(foo, (u8*)&ret, 4);
return ret;
}
#endif
int r_var_item_print(struct r_var_t *var, struct r_var_item_t * v)
{
struct r_var_type_t *t = r_var_type_get(var, v->vartype);
if (t == NULL) {
u32 value = var_dbg_read(v->delta);
// TODO: use var type to
r_cons_printf("%x", value);
} else {
#if 0
u8 buf[1024];
int size = v->arraysize * t->size;
u64 foo = get_offset("ebp");
foo -= v->delta;
//XXX radare_read_at(foo, buf, size);
//eprintf("PRINT_MEM(%llx,%d,%s)\n", foo, size, t->fmt);
//XXX print_mem(foo, buf, size, t->fmt, config.endian);
#endif
}
return 0;
}
/* CFV */
int r_var_list_show(struct r_var_t *var, u64 addr)
{
char buf[256];
struct list_head *pos;
struct r_var_item_t *v;
list_for_each(pos, &var->vars) {
v = (struct r_var_item_t*)list_entry(pos, struct r_var_item_t, list);
if (addr == 0 || (addr >= v->addr && addr <= v->eaddr)) {
u32 value = var_dbg_read(v->delta);
if (v->arraysize>1) {
r_cons_printf("%s %s %s[%d] = ",
r_var_type_to_string(v->type),
v->vartype, v->arraysize, v->name);
} else {
r_cons_printf("%s %s %s = ",
r_var_type_to_string(v->type), v->vartype, v->name);
}
r_var_item_print(var, v);
/* TODO: detect pointer to strings and so on */
#if 0
if (string_flag_offset(buf, value, 0))
r_cons_printf(" ; points to: %s\n", buf);
else
#endif
r_cons_newline();
}
}
return 0;
}
/* 0,0 to list all */
int r_var_list(struct r_var_t *var, u64 addr, int delta)
{
struct list_head *pos, *pos2;
struct r_var_item_t*v;
struct r_var_access_t *x;
list_for_each(pos, &var->vars) {
v = (struct r_var_item_t*)list_entry(pos, struct r_var_item_t, list);
if (addr == 0 || (addr >= v->addr && addr <= v->eaddr)) {
cons_printf("0x%08llx - 0x%08llx type=%s type=%s name=%s delta=%d array=%d\n",
v->addr, v->eaddr, r_var_type_to_string(v->type),
v->vartype, v->name, v->delta, v->arraysize);
list_for_each_prev(pos2, &v->access) {
x = (struct r_var_access_t *)list_entry(pos2, struct r_var_access_t, list);
r_cons_printf(" 0x%08llx %s\n", x->addr, x->set?"set":"get");
}
}
}
return 0;
}
/* analize.c */
// XXX move to code.h
void r_var_anal_reset(struct r_var_t *var)
{
memset(&var->anal, '\0', sizeof(var->anal));
var->anal_size = 0;
}
int r_var_anal_add(struct r_var_t *var, int type, int delta)
{
int i, hole = -1;
for(i=0;i<R_VAR_ANAL_MAX;i++) {
if (var->anal[i].type == type && var->anal[i].delta == delta) {
var->anal[i].count++;
return 0;
} else
if (var->anal[i].type==R_VAR_TYPE_NONE && hole==-1) {
hole = i;
}
}
if (hole==-1) {
fprintf(stderr, "analyze.c: No space left in var pool\n");
return -1;
}
var->anal[hole].type = type;
var->anal[hole].delta = delta;
return 1;
}
int r_var_anal_get(struct r_var_t *var, int type)
{
int i, ctr = 0;
for(i=0;i<R_VAR_ANAL_MAX;i++) {
if (var->anal[i].type == type)
ctr++;
}
return ctr;
}