static int idaapi notify(processor_t::idp_notify msgid, ...) { va_list va; va_start(va, msgid); // A well behaving processor module should call invoke_callbacks() // in his notify() function. If this function returns 0, then // the processor module should process the notification itself // Otherwise the code should be returned to the caller: int code = invoke_callbacks(HT_IDP, msgid, va); if ( code ) return code; switch ( msgid ) { case processor_t::init: // __emit__(0xCC); // debugger trap helper.create("$ h8"); helper.supval(0, device, sizeof(device)); inf.mf = 1; default: break; /* +++ START TYPEINFO CALLBACKS +++ */ // see module/{i960,hppa}/reg.cpp starting on line 253 // Decorate/undecorate a C symbol name // Arguments: // const til_t *ti - pointer to til // const char *name - name of symbol // const type_t *type - type of symbol. If NULL then it will try to guess. // char *outbuf - output buffer // size_t bufsize - size of the output buffer // bool mangle - true-mangle, false-unmangle // cm_t cc - real calling convention for VOIDARG functions // returns: true if success case processor_t::decorate_name: { const til_t *ti = va_arg(va, const til_t *); const char *name = va_arg(va, const char *); const type_t *type = va_arg(va, const type_t *); char *outbuf = va_arg(va, char *); size_t bufsize = va_arg(va, size_t); bool mangle = va_argi(va, bool); cm_t real_cc = va_argi(va, cm_t); return gen_decorate_name(ti, name, type, outbuf, bufsize, mangle, real_cc); } // Setup default type libraries (called after loading a new file into the database) // The processor module may load tils, setup memory model and perform other actions // required to set up the type system. // args: none // returns: nothing case processor_t::setup_til: { } // Purpose: get prefix and size of 'segment based' ptr type (something like // char _ss *ptr). See description in typeinf.hpp. // Other modules simply set the pointer to NULL and return 0 // Ilfak confirmed that this approach is correct for the H8. // Used only for BTMT_CLOSURE types, doubtful you will encounter them for H8. // Arguments: // unsigned int ptrt - ... // const char **ptrname - output arg // returns: size of type case processor_t::based_ptr: { /*unsigned int ptrt =*/ va_arg(va, unsigned int); char **ptrname = va_arg(va, char **); *ptrname = NULL; return 0; } // The H8 supports normal (64KB addressing, 16 bits) and advanced mode // (16MB addressing, 24 bits). However, according to the Renesas technical // documentation, certain instructions accept 32-bit pointer values where // the upper 8 bits are "reserved". Ilfak confirms that "4+1" is fine. // Used only for BTMT_CLOSURE types, doubtful you will encounter them for H8. case processor_t::max_ptr_size: { return 4+1; } // get default enum size // args: cm_t cm // returns: sizeof(enum) case processor_t::get_default_enum_size: { // cm_t cm = va_argi(va, cm_t); return inf.cc.size_e; } case processor_t::use_stkarg_type: { ea_t ea = va_arg(va, ea_t); const type_t *type = va_arg(va, const type_t *); const char *name = va_arg(va, const char *); return h8_use_stkvar_type(ea, type, name); } // calculate number of purged bytes by the given function type // For cdecl functions, 'purged bytes' is always zero // See the IDA Pro Book, 2e, at the end of pp. 107 for details // args: type_t *type - must be function type // returns: number of bytes purged from the stack + 2 case processor_t::calc_purged_bytes: { //e.g. const type_t t_int[] = { BT_INT, 0 }; //const type_t *type = va_arg(va, const type_t *); // must be BT_FUNC return 0+2; } case processor_t::calc_arglocs2: { const type_t *type = va_arg(va, const type_t *); cm_t cc = va_argi(va, cm_t); varloc_t *arglocs = va_arg(va, varloc_t *); return h8_calc_arglocs(type, cc, arglocs); } /* +++ END TYPEINFO CALLBACKS +++ */ case processor_t::term: free_ioports(ports, numports); break; case processor_t::newfile: // new file loaded load_symbols(); break; case processor_t::oldfile: // old file loaded load_symbols(); break; case processor_t::closebase: case processor_t::savebase: helper.supset(0, device); break; case processor_t::newprc: // new processor type ptype = ptypes[va_arg(va, int)]; setflag(ph.flag, PR_DEFSEG32, ptype & ADV); break; case processor_t::newasm: // new assembler type break; case processor_t::newseg: // new segment break; case processor_t::is_jump_func: { const func_t *pfn = va_arg(va, const func_t *); ea_t *jump_target = va_arg(va, ea_t *); return is_jump_func(pfn, jump_target); } case processor_t::is_sane_insn: return is_sane_insn(va_arg(va, int)); case processor_t::may_be_func: // can a function start here? // arg: none, the instruction is in 'cmd' // returns: probability 0..100 // 'cmd' structure is filled upon the entrace // the idp module is allowed to modify 'cmd' return may_be_func(); } va_end(va); return 1; }
int idaapi DBG_Callback(void *ud, int notification_code, va_list va) { // This hook gets called from the kernel. Ensure we hold the GIL. PYW_GIL_GET; class DBG_Hooks *proxy = (class DBG_Hooks *)ud; debug_event_t *event; int code = 0; try { switch (notification_code) { case dbg_process_start: event = va_arg(va, debug_event_t *); proxy->dbg_process_start(event->pid, event->tid, event->ea, event->modinfo.name, event->modinfo.base, event->modinfo.size); break; case dbg_process_exit: event = va_arg(va, debug_event_t *); proxy->dbg_process_exit( event->pid, event->tid, event->ea, event->exit_code); break; case dbg_process_attach: event = va_arg(va, debug_event_t *); proxy->dbg_process_attach( event->pid, event->tid, event->ea, event->modinfo.name, event->modinfo.base, event->modinfo.size); break; case dbg_process_detach: event = va_arg(va, debug_event_t *); proxy->dbg_process_detach( event->pid, event->tid, event->ea); break; case dbg_thread_start: event = va_arg(va, debug_event_t *); proxy->dbg_thread_start( event->pid, event->tid, event->ea); break; case dbg_thread_exit: event = va_arg(va, debug_event_t *); proxy->dbg_thread_exit( event->pid, event->tid, event->ea, event->exit_code); break; case dbg_library_load: event = va_arg(va, debug_event_t *); proxy->dbg_library_load( event->pid, event->tid, event->ea, event->modinfo.name, event->modinfo.base, event->modinfo.size); break; case dbg_library_unload: event = va_arg(va, debug_event_t *); proxy->dbg_library_unload( event->pid, event->tid, event->ea, event->info); break; case dbg_information: event = va_arg(va, debug_event_t *); proxy->dbg_information( event->pid, event->tid, event->ea, event->info); break; case dbg_exception: { event = va_arg(va, debug_event_t *); int *warn = va_arg(va, int *); *warn = proxy->dbg_exception( event->pid, event->tid, event->ea, event->exc.code, event->exc.can_cont, event->exc.ea, event->exc.info); break; } case dbg_suspend_process: proxy->dbg_suspend_process(); break; case dbg_bpt: { thid_t tid = va_arg(va, thid_t); ea_t breakpoint_ea = va_arg(va, ea_t); int *warn = va_arg(va, int *); *warn = proxy->dbg_bpt(tid, breakpoint_ea); break; } case dbg_trace: { thid_t tid = va_arg(va, thid_t); ea_t ip = va_arg(va, ea_t); code = proxy->dbg_trace(tid, ip); break; } case dbg_request_error: { int failed_command = (int)va_argi(va, ui_notification_t); int failed_dbg_notification = (int)va_argi(va, dbg_notification_t); proxy->dbg_request_error(failed_command, failed_dbg_notification); break; } case dbg_step_into: proxy->dbg_step_into(); break; case dbg_step_over: proxy->dbg_step_over(); break; case dbg_run_to: event = va_arg(va, debug_event_t *); proxy->dbg_run_to( event->pid, event->tid, event->ea); break; case dbg_step_until_ret: proxy->dbg_step_until_ret(); break; } } catch (Swig::DirectorException &e) { msg("Exception in DBG Hook function: %s\n", e.getMessage()); if (PyErr_Occurred()) PyErr_Print(); } return code; }
// The kernel event notifications // Here you may take desired actions upon some kernel events static int idaapi notify(processor_t::idp_notify msgid, ...) { va_list va; va_start(va, msgid); // A well behavior processor module should call invoke_callbacks() // in his notify() function. If this function returns 0, then // the processor module should process the notification itself // Otherwise the code should be returned to the caller: int code = invoke_callbacks(HT_IDP, msgid, va); if ( code ) return code; switch ( msgid ) { case processor_t::init: inf.mf = 1; helper.create("$ fr"); default: break; case processor_t::term: free_ioports(ports, numports); break; case processor_t::newfile: choose_device(); set_device_name(device, IORESP_ALL); break; case processor_t::oldfile: { char buf[MAXSTR]; if ( helper.supval(-1, buf, sizeof(buf)) > 0 ) set_device_name(buf, IORESP_NONE); } break; case processor_t::closebase: case processor_t::savebase: helper.supset(-1, device); break; case processor_t::is_basic_block_end: return is_basic_block_end() ? 2 : 0; #ifdef FR_TYPEINFO_SUPPORT // +++ TYPE CALLBACKS case processor_t::max_ptr_size: return 4+1; case processor_t::get_default_enum_size: // get default enum size // args: cm_t cm // returns: sizeof(enum) { // cm_t cm = va_argi(va, cm_t); return 1; // inf.cc.size_e; } case processor_t::based_ptr: { uint ptrt = va_arg(va, unsigned int); qnotused(ptrt); char **ptrname = va_arg(va, char **); *ptrname = NULL; return 0; // returns: size of type } case processor_t::get_stkarg_offset2: // get offset from SP to the first stack argument // args: none // returns: the offset+2 return 0x00 + 2; case processor_t::calc_cdecl_purged_bytes2: // calculate number of purged bytes after call { //ea_t ea = va_arg(va, ea_t); return 0x00 + 2; } #endif // FR_TYPEINFO_SUPPORT #ifdef FR_TINFO_SUPPORT case processor_t::decorate_name3: { qstring *outbuf = va_arg(va, qstring *); const char *name = va_arg(va, const char *); bool mangle = va_argi(va, bool); cm_t cc = va_argi(va, cm_t); return gen_decorate_name3(outbuf, name, mangle, cc) ? 2 : 0; } case processor_t::calc_retloc3: //msg("calc_retloc3\n"); { const tinfo_t *type = va_arg(va, const tinfo_t *); cm_t cc = va_argi(va, cm_t); argloc_t *retloc = va_arg(va, argloc_t *); return calc_fr_retloc(*type, cc, retloc) ? 2 : -1; } break; case processor_t::calc_varglocs3: return 1; // not implemented break; case processor_t::calc_arglocs3: { //msg("calc_arglocs3\n"); func_type_data_t *fti = va_arg(va, func_type_data_t *); return calc_fr_arglocs(fti) ? 2 : -1; } case processor_t::use_stkarg_type3: { //msg("use_stkarg_type3\n"); ea_t ea = va_arg(va, ea_t); const funcarg_t *arg = va_arg(va, const funcarg_t* ); } return false; break; case processor_t::use_regarg_type3: //msg("use_regarg_type3\n"); { int *used = va_arg(va, int *); ea_t ea = va_arg(va, ea_t); const funcargvec_t *rargs = va_arg(va, const funcargvec_t *); *used = use_fr_regarg_type(ea, *rargs); return 2; } break; case processor_t::use_arg_types3: { ea_t ea = va_arg(va, ea_t); func_type_data_t *fti = va_arg(va, func_type_data_t *); funcargvec_t *rargs = va_arg(va, funcargvec_t *); use_fr_arg_types(ea, fti, rargs); return 2; } #ifdef IDA65 case processor_t::get_fastcall_regs2: case processor_t::get_varcall_regs2: { const int **regs = va_arg(va, const int **); return get_fr_fastcall_regs(regs) + 2; } case processor_t::get_thiscall_regs2: { const int **regs = va_arg(va, const int **); *regs = NULL; return 2; } #else case processor_t::get_fastcall_regs3: case processor_t::get_varcall_regs3: { const int *regs; get_fr_fastcall_regs(®s); callregs_t *callregs = va_arg(va, callregs_t *); callregs->set(ARGREGS_INDEPENDENT, regs, NULL); return callregs->nregs + 2; } case processor_t::get_thiscall_regs3: { callregs_t *callregs = va_arg(va, callregs_t *); callregs->reset(); return 2; } #endif IDA65 #endif // FR_TINFO_SUPPORT } va_end(va); return(1); }
static int notify(processor_t::idp_notify msgid, ...) { va_list va; va_start(va, msgid); // A well behaving processor module should call invoke_callbacks() // in his notify() function. If this function returns 0, then // the processor module should process the notification itself // Otherwise the code should be returned to the caller: int code = invoke_callbacks(HT_IDP, msgid, va); if ( code ) return code; switch(msgid) { case processor_t::init: // __emit__(0xCC); // debugger trap helper.create("$ hppa"); inf.mf = 1; // always big endian syscalls = read_ioports(&nsyscalls, "hpux.cfg", NULL, 0, NULL); break; case processor_t::term: free_ioports(syscalls, nsyscalls); break; case processor_t::newfile: // new file loaded handle_new_flags(); setup_got(); break; case processor_t::oldfile: // old file loaded idpflags = helper.altval(-1); handle_new_flags(); setup_got(); break; case processor_t::newprc: // new processor type break; case processor_t::newasm: // new assembler type break; case processor_t::newseg: // new segment { segment_t *sptr = va_arg(va, segment_t *); sptr->defsr[ rVds-ph.regFirstSreg] = find_selector(sptr->sel); sptr->defsr[DPSEG-ph.regFirstSreg] = 0; } break; case processor_t::is_sane_insn: return is_sane_insn(va_arg(va, int)); case processor_t::may_be_func: // can a function start here? // arg: none, the instruction is in 'cmd' // returns: probability 0..100 // 'cmd' structure is filled upon the entrace // the idp module is allowed to modify 'cmd' return may_be_func(); case processor_t::is_basic_block_end: return is_basic_block_end() ? 2 : 0; // +++ TYPE CALLBACKS (only 32-bit programs for the moment) case processor_t::decorate_name: { const til_t *ti = va_arg(va, const til_t *); const char *name = va_arg(va, const char *); const type_t *type = va_arg(va, const type_t *); char *outbuf = va_arg(va, char *); size_t bufsize = va_arg(va, size_t); bool mangle = va_argi(va, bool); cm_t real_cc = va_argi(va, cm_t); return gen_decorate_name(ti, name, type, outbuf, bufsize, mangle, real_cc); } case processor_t::max_ptr_size: return 4+1; case processor_t::based_ptr: { /*unsigned int ptrt =*/ va_arg(va, unsigned int); char **ptrname = va_arg(va, char **); *ptrname = NULL; return 0; // returns: size of type } case processor_t::get_default_enum_size: // get default enum size // args: cm_t cm // returns: sizeof(enum) { // cm_t cm = va_arg(va, cm_t); return inf.cc.size_e; } case processor_t::calc_arglocs: { const type_t **type = va_arg(va, const type_t **); ulong *arglocs = va_arg(va, ulong *); int maxn = va_arg(va, int); return hppa_calc_arglocs(*type, arglocs, maxn); } // this callback is never used because the stack pointer does not // change for each argument // we use ph.use_arg_types instead case processor_t::use_stkarg_type: // use information about a stack argument { return false; // say failed all the time // so that the kernel attaches a comment } case processor_t::use_regarg_type: { ea_t ea = va_arg(va, ea_t); const type_t * const *types = va_arg(va, const type_t * const *); const char * const *names = va_arg(va, const char * const *); const ulong *regs = va_arg(va, const ulong *); int n = va_arg(va, int); return hppa_use_regvar_type(ea, types, names, regs, n); } case processor_t::use_arg_types: { ea_t ea = va_arg(va, ea_t); const type_t * const *types = va_arg(va, const type_t * const *); const char * const *names = va_arg(va, const char * const *); const ulong *arglocs = va_arg(va, const ulong *); int n = va_arg(va, int); const type_t **rtypes = va_arg(va, const type_t **); const char **rnames = va_arg(va, const char **); ulong *regs = va_arg(va, ulong *); int rn = va_arg(va, int); return hppa_use_arg_types(ea, types, names, arglocs, n, rtypes, rnames, regs, rn); } case processor_t::get_fastcall_regs: { const int **regs = va_arg(va, const int **); static const int fregs[] = { R26, R25, R24, R23, -1 }; *regs = fregs; return qnumber(fregs) - 1; } case processor_t::get_thiscall_regs: { const int **regs = va_arg(va, const int **); *regs = NULL; return 0; } case processor_t::calc_cdecl_purged_bytes: // calculate number of purged bytes after call { // ea_t ea = va_arg(va, ea_t); return 0; } case processor_t::get_stkarg_offset: // get offset from SP to the first stack argument // args: none // returns: the offset return -0x34; // --- TYPE CALLBACKS case processor_t::loader: break; } va_end(va); return 1; }