[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