[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
add a very useful command to ddb
unlike n/p, yzw command use another way to print more readable infomation
of function's calling tree, and their arguments.
here is an example:
ddb> br amap_alloc
ddb> c
Breakpoint at _amap_alloc: pushl %ebp
ddb> y/e
e01cc627: __pool_get(0xe0272338,0,0xe01cc580,0xb4)
e01cc671: _malloc(4,0x62,1,0x382)
e013da11: _debug_malloc(4,0x62,1,0xf03cfda4)
e013dddf: _uvm_map_checkprot(0xe0257b4c,0xe0709600,0xe070960c,2)
e01d4a5e:
_uvm_map_lookup_entry(0xe0257b4c,0xe0709600,0xf03cfd44,0x396)
e01cc68a: _malloc(4,0x62,1,0x386)
e013da11: _debug_malloc(4,0x62,1,0xf03cfda4)
e013dddf: _uvm_map_checkprot(0xe0257b4c,0xe0709d70,0xe0709d7c,2)
e01d4a5e:
_uvm_map_lookup_entry(0xe0257b4c,0xe0709d70,0xf03cfd44,0x396)
e01cc6a3: _malloc(4,0x62,1,0x386)
e013da11: _debug_malloc(4,0x62,1,0xf03cfda4)
e013dddf: _uvm_map_checkprot(0xe0257b4c,0xe0709210,0xe070921c,2)
e01d4a5e:
_uvm_map_lookup_entry(0xe0257b4c,0xe0709210,0xf03cfd44,0x396)
e01cc702: _memset(0xe0709d70,0,4,0x382)
Stopped at _amap_alloc+0x150: ret
see, it's good enough to debug a function quickly without stepping into it,
with just one command, we can monitor all the arguments we passed in.
also, we can limit calling tree in modules in order to avoid some boring
functions' calling tree, like printf
here is the way:
1 using nm to generate a list of kernel symbols
nm /bsd | sort
2 search for your interested xxx.o or symbols
e01cc0c0 F uvm_amap.o
3 set the begin position
ddb> w db_yzw_begin 0xe01cc0c0
_db_yzw_begin 0 = 0xe01cc0c0
4 also, you can set the end position by writing db_yzw_end
and the yzw command accept these modifiers:
/a: don't print any argument
/b: print one argument
/c: print two arguments
/d: print three arguments
and so on.
I don't generate a patch because I modified these codes on an early version
of OpenBSD.
so follow me to modify them manually:
step1 in db_run.h:
search for db_trace_until_matching_cmd, add following line below it:
void db_yzw_cmd __P((db_expr_t, int, db_expr_t, char *));
step2 in db_command.c:
search for hangman, add following line under it:
{ "yzw", db_yzw_cmd, 0, NULL },
step3 in db_run.c:
search for STEP_COUNT, add follwing lines under it
#define STEP_YZW 7
void printf(const char *fmt, ...);
u_long db_yzw_begin = 0, db_yzw_end = 0xffffffff;
static u_long yzw_call_pc = 0;
static u_long yzw_call_print = 0;
static u_long yzw_call_nargs = 0;
step4 in db_run.c:
in db_stop_at_pc(), add these codes like STEP_RETURN does
if (db_run_mode == STEP_YZW) {
db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
do {
if ( inst_trap_return(ins) ) break;
if ( inst_return(ins) ) {
db_call_depth--;
if ( db_call_depth == 0 ) break;
return FALSE;
}
if ( inst_call(ins) ) {
db_call_depth++;
yzw_call_pc = pc;
yzw_call_print = 1;
return FALSE;
}
while ( yzw_call_print ) {
register int i;
char *sym1;
u_long symoff1;
char *name1;
yzw_call_print = 0;
if ( pc < db_yzw_begin || pc > db_yzw_end ) break;
sym1 = db_search_symbol(pc, 0, &symoff1);
db_symbol_values(sym1, &name1, NULL);
printf("%x:", yzw_call_pc);
for (i = db_call_depth; --i > 1; ) printf(" ");
if ( symoff1 ) printf(" %s+%x", name1, symoff1);
else printf(" %s", name1);
if ( yzw_call_nargs <= 0 ) {
printf("\n");
break;
}
printf("(");
for (i = 0; i < yzw_call_nargs; i++ ) {
register u_long a;
if ( i ) printf(",");
a = *(u_long *)(regs->tf_esp + 4 + i * 4);
if ( a > 9 ) printf("0x%x", a);
else printf("%d", a);
}
printf(")\n");
break;
}
return (FALSE); /* continue */
} while(0);
}
step 5: in db_run.c
add this function:
/*ARGSUSED*/
void
db_yzw_cmd(addr, have_addr, count, modif)
db_expr_t addr;
int have_addr;
db_expr_t count;
char * modif;
{
int new_nargs;
new_nargs = *modif - 'a';
if ( new_nargs >= 0 && new_nargs <= 9 ) {
yzw_call_nargs = new_nargs;
}
db_run_mode = STEP_YZW;
db_call_depth = 1;
db_sstep_print = TRUE;
db_inst_count = 0;
db_load_count = 0;
db_store_count = 0;
db_cmd_loop_done = 1;
}
that's enough, note that I only test it on i386 arch, I have no knowledge
about other archs
Enjoy it.
- Yang Zhiwei