trap_retval ReqProg_go( void ) { return( ProgRun( FALSE ) ); }
trap_retval ReqProg_step( void ) { return( ProgRun( TRUE ) ); }
unsigned ReqProg_step( void ) /***************************/ { return( ProgRun( TRUE ) ); }
unsigned ReqProg_go( void ) /*************************/ { return( ProgRun( FALSE ) ); }
unsigned ReqProg_step() { return( ProgRun( TRUE ) ); }
unsigned ReqProg_go() { return( ProgRun( FALSE ) ); }
static unsigned ProgRun( int step ) { static int ptrace_sig = 0; static int ld_state = 0; user_regs_struct regs; int status; prog_go_ret *ret; void (*old)(int); int debug_continue; if( pid == 0 ) return( 0 ); ret = GetOutPtr( 0 ); if( at_end ) { ptrace_sig = 0; ret->conditions = COND_TERMINATE; goto end; } /* we only want child-generated SIGINTs now */ do { old = setsig( SIGINT, SIG_IGN ); if( step ) { Out( "PTRACE_SINGLESTEP\n" ); if( ptrace( PTRACE_SINGLESTEP, pid, NULL, (void *)ptrace_sig ) == -1 ) perror( "PTRACE_SINGLESTEP" ); } else { Out( "PTRACE_CONT\n" ); if( ptrace( PTRACE_CONT, pid, NULL, (void *)ptrace_sig ) == -1 ) perror( "PTRACE_CONT" ); } waitpid( pid, &status, 0 ); setsig( SIGINT, old ); #if defined( MD_x86 ) ptrace( PTRACE_GETREGS, pid, NULL, ®s ); #elif defined( MD_ppc ) regs.eip = ptrace( PTRACE_PEEKUSER, pid, REGSIZE * PT_NIP, NULL ); regs.esp = ptrace( PTRACE_PEEKUSER, pid, REGSIZE * PT_R1, NULL ); #elif defined( MD_mips ) regs.eip = ptrace( PTRACE_PEEKUSER, pid, (void *)PC, NULL ); regs.esp = ptrace( PTRACE_PEEKUSER, pid, (void *)29, NULL ); #endif Out( " eip " ); OutNum( regs.eip ); Out( "\n" ); debug_continue = FALSE; if( WIFSTOPPED( status ) ) { switch( ( ptrace_sig = WSTOPSIG( status ) ) ) { case SIGSEGV: case SIGILL: case SIGFPE: case SIGABRT: case SIGBUS: case SIGQUIT: case SIGSYS: last_sig = ptrace_sig; ret->conditions = COND_EXCEPTION; ptrace_sig = 0; break; case SIGINT: ret->conditions = COND_USER; ptrace_sig = 0; break; case SIGTRAP: ret->conditions = step ? COND_TRACE : COND_BREAK; Out( "sigtrap\n" ); ptrace_sig = 0; break; default: /* For signals that we do not wish to handle, we need * to continue the debuggee until we get a signal * that we need to handle */ Out( "Unknown signal " ); OutNum( ptrace_sig ); Out( "\n" ); debug_continue = TRUE; break; } } else if( WIFEXITED( status ) ) { Out( "WIFEXITED\n" ); at_end = TRUE; ret->conditions = COND_TERMINATE; ptrace_sig = 0; goto end; } } while( debug_continue ); if( ret->conditions == COND_BREAK ) { #if defined( MD_x86 ) if( regs.eip == rdebug.r_brk + sizeof( old_ld_bp ) ) { #elif defined( MD_ppc ) || defined( MD_mips ) if( regs.eip == rdebug.r_brk ) { #endif int psig = 0; void (*oldsig)(int); bp_t opcode = BRK_POINT; /* The dynamic linker breakpoint was hit, meaning that * libraries are being loaded or unloaded. This gets a bit * tricky because we must restore the original code that was * at the breakpoint and execute it, but we still want to * keep the breakpoint. */ WriteMem( pid, &old_ld_bp, rdebug.r_brk, sizeof( old_ld_bp ) ); ReadMem( pid, &rdebug, (addr48_off)dbg_rdebug, sizeof( rdebug ) ); Out( "ld breakpoint hit, state is " ); switch( rdebug.r_state ) { case RT_ADD: Out( "RT_ADD\n" ); ld_state = RT_ADD; AddOneLib( rdebug.r_map ); break; case RT_DELETE: Out( "RT_DELETE\n" ); ld_state = RT_DELETE; break; case RT_CONSISTENT: Out( "RT_CONSISTENT\n" ); if( ld_state == RT_DELETE ) DelOneLib( rdebug.r_map ); ld_state = RT_CONSISTENT; break; default: Out( "error!\n" ); break; } regs.orig_eax = -1; #if defined( MD_x86 ) regs.eip--; ptrace( PTRACE_SETREGS, pid, NULL, ®s ); #endif oldsig = setsig( SIGINT, SIG_IGN ); ptrace( PTRACE_SINGLESTEP, pid, NULL, (void *)psig ); waitpid( pid, &status, 0 ); setsig( SIGINT, oldsig ); WriteMem( pid, &opcode, rdebug.r_brk, sizeof( old_ld_bp ) ); ret->conditions = COND_LIBRARIES; } else { #if defined( MD_x86 ) Out( "decrease eip(sigtrap)\n" ); regs.orig_eax = -1; regs.eip--; ptrace( PTRACE_SETREGS, pid, NULL, ®s ); #endif } } orig_eax = regs.orig_eax; last_eip = regs.eip; ret->program_counter.offset = regs.eip; ret->program_counter.segment = regs.cs; ret->stack_pointer.offset = regs.esp; ret->stack_pointer.segment = regs.ss; ret->conditions |= COND_CONFIG; /* If debuggee has dynamic section, try getting the r_debug struct * every time the debuggee stops. The r_debug data may not be available * immediately after the debuggee process loads. */ if( !have_rdebug && (dbg_dyn != NULL) ) { if( Get_ld_info( pid, dbg_dyn, &rdebug, &dbg_rdebug ) ) { bp_t opcode; AddInitialLibs( rdebug.r_map ); have_rdebug = TRUE; ret->conditions |= COND_LIBRARIES; /* Set a breakpoint in dynamic linker. That way we can be * informed on dynamic library load/unload events. */ ReadMem( pid, &old_ld_bp, rdebug.r_brk, sizeof( old_ld_bp ) ); Out( "Setting ld breakpoint at " ); OutNum( rdebug.r_brk ); Out( " old opcode was " ); OutNum( old_ld_bp ); Out( "\n" ); opcode = BRK_POINT; WriteMem( pid, &opcode, rdebug.r_brk, sizeof( opcode ) ); } } end: CONV_LE_32( ret->stack_pointer.offset ); CONV_LE_16( ret->stack_pointer.segment ); CONV_LE_32( ret->program_counter.offset ); CONV_LE_16( ret->program_counter.segment ); CONV_LE_16( ret->conditions ); return( sizeof( *ret ) ); } unsigned ReqProg_step( void ) { return( ProgRun( TRUE ) ); } unsigned ReqProg_go( void ) { return( ProgRun( FALSE ) ); } unsigned ReqRedirect_stdin( void ) { redirect_stdin_ret *ret; ret = GetOutPtr( 0 ); ret->err = 1; return( sizeof( *ret ) ); }