def __init__(self): addr = toAddr('levent_table') if addr is None: raise ValueError('levent_table not found, check stubs or run ImportCHDKStubs.py') self.list=[] self.by_name = {} self.by_id = {} while True: evdef = get_levent_def_at(addr) if evdef is None: break self.list.append(evdef) if evdef['id'] not in self.by_id: self.by_id[evdef['id']] = evdef else: warn("dupe event id %x"%(evdef['id'])) if evdef['name'] != '': if evdef['name'] not in self.by_name: self.by_name[evdef['name']] = evdef else: warn("dupe event name %s"%(evdef['name'])) addr = addr.add(12)
def create_bytemap(self, mbdef): addr = toAddr(mbdef['start']) src_addr = toAddr(mbdef['src']) mb_src = getMemoryBlock(src_addr) if not mb_src: warn("mblock %s bytemap no source block found" % (mbdef['name'])) return infomsg( 0, "Create bytemap mblock %s 0x%s 0x%x (%d) from %s %s\n" % (mbdef['name'], addr, mbdef['size'], mbdef['size'], mb_src.getName(), src_addr)) if g_options['pretend']: return mem = getCurrentProgram().getMemory() # API changed in 9.2, added "overlay" bool if ghidra.framework.ApplicationVersion(getGhidraVersion( )) >= ghidra.framework.ApplicationVersion('9.2'): mem.createByteMappedBlock(mbdef['name'], addr, src_addr, mbdef['size'], False) else: mem.createByteMappedBlock(mbdef['name'], addr, src_addr, mbdef['size']) mb_new = getMemoryBlock(addr) self.set_attrs(mbdef, mb_new)
def do_after_pop_list(l): for v in l: # disassemble directly to force tmode, allow checking invalid idesc = get_insn_desc(v[0], disassemble=True, dis_tmode=v[2]) r = idesc.is_likely_after_pop() if r != v[1]: warn('after_pop fail %s %s != %s %s' % (v[0], r, v[1], idesc.insn))
def merge_blocks(self): '''merge adjacent blocks to reduce CHDK core data''' blocks = [] pb = None for b in sorted(self.blocks, key=lambda b: b['offset']): if pb: infomsg( 2, '%s %s %x\n' % (pb['name'], b['name'], b['offset'] - (pb['offset'] + pb['size']))) pb_end = pb['offset'] + pb['size'] # should be handled correctly, but may indicate incorrect block detection if pb_end > b['offset']: warn('overlapping blocks %s %s\n' % (pb['name'], b['name'])) # allow a modest fudge, assuming Canon wouldn't put a varying chunk in a small space if b['offset'] <= pb['offset'] + pb['size'] + 32: nb = pb nb['name'] += ', ' + b['name'] nb['size'] += b['size'] + b['offset'] - (pb['offset'] + pb['size']) pb = nb continue pb = b blocks.append(b) self.blocks = blocks
def init_levent_table(): addr = toAddr('levent_table') if addr is None: raise ValueError('levent_table not found, check stubs or run ImportCHDKStubs.py') cnt = 0 while True: try: pname = get_valid_pointer_at(addr) if pname is None or getInt(addr.add(4)) == -1: infomsg(0,'break\n') break clearListing(addr, addr.add(11)) b = getByte(pname) # if it looks like a string if is_print_char(b): # if preceding is null, and address isn't already inside data, make string if getByte(pname.add(-1)) == 0 and getDataContaining(pname) == None: createAsciiString(pname) createData(addr, Pointer32DataType()) createDwords(addr.add(4),2) addr = addr.add(12) cnt += 1 except(ghidra.program.model.mem.MemoryAccessException): warn("Memory access exception at %s"%(addr)) break infomsg(0,'levent_table %s %d entries\n'%(toAddr('levent_table'),cnt))
def list_mzrm_create_calls(): filename = str(askFile("mzrm id list", "select")) mzrmlist = MzrmMsgList(filename) cd = MzrmCallDescriber(mzrmlist) instr = str(askString("MZRM Messages", "Names, numbers or *")).upper() mzrm_ids = [] do_all = False for s in re.split('[ ,]+', instr): if s == '*': do_all = True elif re.match('0x[0-9a-f]+$', s, re.I): mzrm_ids.append(int(s, 16)) elif re.match('[0-9]+$', s): mzrm_ids.append(int(s, 10)) else: mzrm_msg = mzrmlist.by_name.get(s) if mzrm_msg is None: # iterate over list for case insensitive compare for mzrm_id in mzrmlist.by_id: if mzrmlist.by_id[mzrm_id].name.lower() == s.lower(): mzrm_msg = mzrmlist.by_id[mzrm_id] break if mzrm_msg is None: warn('ignoring unknown mesasge id %s' % (s)) else: mzrm_ids.append(mzrm_msg.mid) if len(mzrm_ids) == 0 and not do_all: warn('no valid IDs specified, exiting') return infomsg(0, "Searching for") msg = [] if do_all: msg.append('all known') for mzrm_id in mzrm_ids: if mzrm_id in mzrmlist.by_id and not mzrmlist.by_id[mzrm_id].unk: msg.append("%s (%d)" % (mzrmlist.by_id[mzrm_id].name, mzrm_id)) else: msg.append("%d" % (mzrm_id)) infomsg(0, " %s\n" % (', '.join(msg))) for desc in cd.describe_all_calls(): mzrm_id = desc.args[2].val if (do_all and mzrmlist.by_id.get(mzrm_id)) or mzrm_id in mzrm_ids: infomsg( 0, '%s %s(%s,%s,%s,%s)\n' % (desc.addr, desc.fname, desc.args[0].desc, desc.args[1].desc, desc.args[2].desc, desc.args[3].desc))
def process_thumb_notdis_label(addr, t_addr): # no instruction, look for possible code for ref in getReferencesTo(t_addr): idesc = get_insn_desc(ref.getFromAddress()) if idesc is None: continue # tbb instructions create weird refs # also don't want anything ref'd by lrdb # mvn almost always constants that look like addresses # mov could be suspect, but also valid since ghidra tracks load + mov mne = idesc.get_mne() if mne == 'tbb' or mne == 'tbh' or mne == 'ldrb' or mne == 'mvn': # infomsg(0,"%s skip ref %s\n"%(addr,mne)) return False if not is_likely_func_start( addr, require_push=False, disassemble=True, tmode=True): return False # infomsg(0,"%s dis thumb\n"%(addr)) bad_data = getDataAt(t_addr) if bad_data: if g_options['verbose']: infomsg(0, '%s remove data %s\n' % (t_addr, bad_data)) if not g_options['pretend']: removeData(bad_data) else: # check for data containing bad_data = getDataContaining(addr) # if it's also unaligned, assume bad # could check for other signs of validity, but already have valid func start if bad_data and (bad_data.getAddress().getOffset() & 1 == 1): if g_options['verbose']: infomsg(0, '%s remove containing data %s\n' % (t_addr, bad_data)) if not g_options['pretend']: removeData(bad_data) # if existing function without disassembled code, remove and try to recreate old_fn = getFunctionAt(addr) if old_fn: # infomsg(0,'%s remove func\n'%(addr)) if not g_options['pretend']: removeFunction(old_fn) if not g_options['pretend']: # set thumb since this case is only used when address has thumb bit set set_tmode_reg_at(addr, 1) if not disassemble(addr): warn("%s dis fail" % (addr)) return False if g_options['verbose']: infomsg(0, '%s thumb data dis func\n' % (addr)) return do_make_func(addr)
def add_block(self, blk): b = blk.copy() if b['offset'] >= self.filesize: warn("block %s start outside file, ignored" % (b['name'])) b['size'] = 0 elif self.filesize - b['offset'] < b['size']: warn("block %s end outside file, truncated" % (b['name'])) b['size'] = self.filesize - b['offset'] self.total_size += b['size'] self.blocks.append(b)
def list_levent_calls(): cd = LeventCallDescriber() instr = str(askString("Event","Names, numbers or *")).upper() event_ids = [] do_all = False for s in re.split('[ ,]+',instr): if s == '*': do_all = True elif re.match('0x[0-9a-f]+$',s,re.I): event_ids.append(int(s,16)) elif re.match('[0-9]+$',s): event_ids.append(int(s,10)) else: event_id = cd.ld.by_name.get(s) if event_id is None: # iterate over list for case insensitive compare for evdef in cd.ld.list: if evdef['name'].lower() == s.lower(): event_id = evdef['id'] break if event_id is None: warn('ignoring unknown event id %s'%(s)) else: event_ids.append(event_id) if len(event_ids) == 0 and not do_all: warn('no valid IDs specified, exiting') return infomsg(0,"Searching for") msg = [] if do_all: msg.append('all known') for event_id in event_ids: if event_id in cd.ld.by_id and cd.ld.by_id[event_id]['name'] !='': msg.append("%s (%d)"%(cd.ld.by_id[event_id]['name'],event_id)) else: msg.append("%d"%(event_id)) infomsg(0," %s\n"%(', '.join(msg))) for desc in cd.describe_all_calls(): event_id = desc.args[0].val if (do_all and cd.ld.by_id.get(event_id)) or event_id in event_ids: infomsg(0,'%s %s(%s'%(desc.addr,desc.fname,desc.args[0].desc)) if len(desc.args) == 2: infomsg(0,', %s'%(desc.args[1].desc)) infomsg(0,')\n')
def list_prop_calls(): filename = str(askFile("platform_camera.h or propsetN.h", "select")) instr = str(askString("Propcases", "Names, numbers or *")).upper() pd = PropsetData(filename) prop_ids = [] do_all = False for s in re.split('[ ,]+', instr): if s == '*': do_all = True elif re.match('0x[0-9a-f]+$', s, re.I): prop_ids.append(int(s, 16)) elif re.match('[0-9]+$', s): prop_ids.append(int(s, 10)) else: if re.match('^PROPCASE_', s): prop_name = s else: prop_name = 'PROPCASE_' + s prop_id = pd.by_name.get(prop_name) if prop_id is None: warn('ignoring unknown propcase id %s' % (prop_name)) else: prop_ids.append(prop_id) if len(prop_ids) == 0 and not do_all: warn('no valid IDs specified, exiting') return infomsg(0, "Searching for") msg = [] if do_all: msg.append('all known') for prop_id in prop_ids: if prop_id in pd.by_id: msg.append("%s (%d)" % (pd.by_id[prop_id], prop_id)) else: msg.append("%d" % (prop_id)) infomsg(0, " %s from propset %d\n" % (', '.join(msg), pd.propset)) cd = PropCallDescriber(filename) for desc in cd.describe_all_calls(): prop_id = desc.args[0].val if (do_all and pd.by_id.get(prop_id)) or prop_id in prop_ids: infomsg( 0, '%s %s(%s,%s,%s)\n' % (desc.addr, desc.fname, desc.args[0].desc, desc.args[1].desc, desc.args[2].desc))
def set_tmode_reg_at(address, tmode): """attempt to set thumb mode register at address, true if register set""" # for thumb "register" value, will be None if not a thumb capable processor progCtx = getCurrentProgram().getProgramContext() tmodeReg = progCtx.getRegister("TMode") try: if tmode == 1: if tmodeReg: progCtx.setValue(tmodeReg, address, address, BigInteger("1")) else: warn("Thumb bit set without TMode register %s" % (address)) else: progCtx.setValue(tmodeReg, address, address, BigInteger("0")) return True except ghidra.program.model.listing.ContextChangeException: warn("Set tmode failed at %s" % (address)) return False
def create_split(self, mbdef): addr = toAddr(mbdef['start']) mb_src = getMemoryBlock(addr) if not mb_src: warn("mblock %s split no source block found" % (mbdef['name'])) return infomsg( 0, "Create split mblock %s 0x%s from %s\n" % (mbdef['name'], addr, mb_src.getName())) if g_options['pretend']: return mem = getCurrentProgram().getMemory() mem.split(mb_src, addr) mb_new = getMemoryBlock(addr) mb_new.setName(mbdef['name']) self.set_attrs(mbdef, mb_new)
def do_make_func(addr): infomsg(0,'make func %s\n'%(addr)); fc = getFunctionContaining(addr) f_addr = None if fc: infomsg(0,'%s already part of function %s\n'%(addr, fc.getName())) fb = fc.getBody() # check if containing function is non-contiguous (often, but not always incorrect) if fb.getNumAddressRanges() > 1: r = fb.getRangeContaining(addr) # if our func is start of non-contiguous func, remove it if r.getMinAddress() == addr: infomsg(0,'remove %s from %s %s\n'%(addr,fc.getName(),fc.getSymbol().address)) if not g_options['pretend']: s = fc.getSymbol() if s.getSource() == SourceType.ANALYSIS or s.getSource() == SourceType.DEFAULT: f_addr = fc.getSymbol().address removeFunction(fc) else: infomsg(0,'not removing non-default source function %s\n'%(fc.getName())) # removing from fc body doesn't seem reliable, works for some? # fb.delete(r) # fc.setBody(AddressSet(fb)) # analyzeChanges(currentProgram) if g_options['pretend']: return True f = createFunction(addr,None) if f_addr: fr = createFunction(f_addr,None) if fr: infomsg(0,'recreated %s at %s\n'%(fr.getName(),f_addr)) else: infomsg(0,'failed to re-create function at %s\n'%(f_addr)) if f: return True else: warn('create function failed %s'%(addr)) return False
def process_dump(dump_name,out_dir,stubs_data): if not os.path.isfile(dump_name): warn("missing %s"%(dump_name)) return dumper = BlobDumper(dump_name) if dumper.filesize == 0: warn("zero size %s"%(dump_name)) return dumper.process_stubs(stubs_data) with open(dump_name,'rb') as fh: for b in dumper.blocks: oname = os.path.join(out_dir,b['name']+'.bin') fh.seek(b['offset']) data = fh.read(b['size']) infomsg(0,'Write %s 0x%08x %s\n'%(oname,b['start_adr'],b['size'])) with open(oname,'wb') as ofh: ofh.write(data)
def load_options(secname, cfgfile, options_spec, options): # initialize with default values for ospec in options_spec: options[ospec['name']] = ospec['default'] if not os.path.isfile(cfgfile): infomsg(0, 'Config not found %s\n' % (cfgfile)) return True missing = False # lets caller bypass if options['skip_load_config']: infomsg(0, 'Skip load config %s\n' % (cfgfile)) else: config = ConfigParser.ConfigParser() infomsg(0, 'Load config %s\n' % (cfgfile)) config.read(cfgfile) if config.has_section(secname): for ospec in options_spec: k = ospec['name'] if not config.has_option(secname, k): missing = True continue vt = ospec['type'] if vt == 'bool': options[k] = config.getboolean(secname, k) elif vt == 'int': options[k] = config.getint(secname, k) elif vt == 'enum': cv = config.get(secname, k) if cv in ospec['vals']: options[k] = cv else: warn("unexpected cfg option %s %s" % (k, cv)) else: warn("unexpected option desc %s" % (k)) else: missing = True return missing
def write_options(secname, cfgfile, options_spec, options): # lets caller bypass if options['skip_create_config']: infomsg(0, "Skip writing config file %s\n" % (cfgfile)) return infomsg(0, "Writing config file %s\n" % (cfgfile)) try: fh = open(cfgfile, "w") fh.write('[' + secname + ']\n') for ospec in options_spec: k = ospec['name'] fh.write('# {} {} default={}\n'.format(k, ospec['type'], ospec['default'])) fh.write(ospec['desc']) # this is g_options, to allow merging. Should always have been initialized from defaults, at least fh.write('{}={}\n\n'.format(k, options[k])) fh.close() except IOError: warn('saving default cfg failed')
def get_pinsn_at(address, thumb=False): """ attempt to dissemble adr, return PseudoInstruction or None for pre-analysis without affecting program """ # NOTE in modules used from interpreter window, using the currentProgram # variable fails on tab switches (currentProgram is set at import time) cp = getCurrentProgram() mbi = MemoryBufferImpl(cp.getMemory(), address) # API changed in 9.2 if ghidra.framework.ApplicationVersion( getGhidraVersion()) >= ghidra.framework.ApplicationVersion('9.2'): pci = ProcessorContextImpl(cp.getLanguage()) else: pci = ProcessorContextImpl(cp.getProgramContext().getRegisters()) treg = pci.getRegister('TMode') # don't try to set thumb reg if firmware not loaded as t if treg: if thumb: pci.setValue(pci.getRegister('TMode'), BigInteger("1")) else: pci.setValue(pci.getRegister('TMode'), BigInteger("0")) elif thumb: warn("ignoring Thumb set on non-t processor") try: ip = cp.getLanguage().parse(mbi, pci, False) pi = PseudoInstruction(address, ip, mbi, pci) return pi except (ghidra.program.model.lang.UnknownInstructionException, ghidra.program.model.lang.InsufficientBytesException, ghidra.program.model.address.AddressOverflowException): return None
def process_dump(sub, dump_name, stubs_data, custom_blocks=None): if not os.path.isfile(dump_name): warn("missing %s" % (dump_name)) return csums = ChecksumInfo(dump_name) if csums.filesize == 0: warn("zero size %s" % (dump_name)) return if custom_blocks: csums.process_custom(stubs_data, custom_blocks) else: csums.process_stubs(stubs_data) canon_sub = (sub[0] + '.' + sub[1:]).upper() # most cams version starts with GM, a few early ones don't # assumes all firmware of a given model either do or don't if stubs_data.stubs_entry_misc['fw_ver_info']['verstr'][0:2] == 'GM': canon_sub = 'GM' + canon_sub # sanity check that our inferred firmware version appears in the dump at the expected place ver_offset = stubs_data.stubs_entry_misc['fw_ver_info'][ 'verstr_adr'] - stubs_data.stubs_entry_misc['ar_rom']['start_adr'] if ver_offset + len(canon_sub) <= csums.filesize: with open(dump_name, 'rb') as fh: fh.seek(ver_offset) dump_sub = fh.read(len(canon_sub)) if bytes(canon_sub, 'utf8') != dump_sub: warn("Version string %s does not match dump %s" % (canon_sub, dump_sub)) return else: warn("Version string outside dump, not verified") return { 'sub': sub, 'canon_sub': canon_sub, 'csums': csums, }
def list_calls_main(): funcstr = str(askString("Function", "Name or address")) s = getSymbol(funcstr, None) if s: if s.getSymbolType() != SymbolType.FUNCTION: warn('symbol %s is not a function, exiting' % (s)) return addr = s.getAddress() else: addr = toAddr(funcstr) if not addr: warn('%s could not be converted to address, exiting' % (funcstr)) return func = getFunctionAt(addr) if not func: warn('no function at %s, exiting' % (addr)) return argstr = str(askString("Arguments 0-3", "numbers or - to ignore")).upper() n = 0 matches = [] regs = {} msg = [] match_arg_count = 0 for s in re.split('[ ,]+', argstr): if n > 3: warn('too many arguments, exiting' % (addr)) return if s == '-': match_val = None elif re.match('0x[0-9a-f]+$', s, re.I): match_val = int(s, 16) elif re.match('[0-9]+$', s): match_val = int(s, 10) else: warn('did not understand %s, exiting' % (s)) return regs['r%d' % (n)] = {'type': 'int'} matches.append(match_val) if match_val is not None: match_arg_count += 1 msg.append('0x%x' % (match_val)) else: msg.append('-') n += 1 if len(regs) == 0: warn('no arguments, exiting' % (s)) msg_str = ', '.join(msg) infomsg(0, "Searching for %s(%s)\n" % (func.getName(), msg_str)) funcdesc = {func.getName(): regs} cd = CallDescriber(funcdesc) for desc in cd.describe_all_calls(): match_count = 0 for i, v in enumerate(matches): if v is None: continue if v == desc.args[i].val: match_count += 1 if match_count == match_arg_count: infomsg(0, '%s %s(%s)\n' % (desc.addr, desc.fname, msg_str))
def do_likely_tail_call_list(l): for v in l: addr = toAddr(v[0]) r = is_likely_tail_call(addr) if r != v[1]: warn('tail_call fail %s %s != %s' % (addr, r, v[1]))
def init_chdk_mem_map_main(): init_options() stubs_data = StubsData(warnfunc=warn, infofunc=infomsg) # whatever askDirectory returns isn't actually string sub_dir = str(askDirectory("CHDK platform sub", "select")) filepath = os.path.join(sub_dir, 'stubs_entry.S') if not os.path.isfile(filepath): infomsg(0, 'No stubs_entry.S, trying stubs_entry.S.err\n') filepath = os.path.join(sub_dir, 'stubs_entry.S.err') if not os.path.isfile(filepath): warn('No stubs_entry files found') return stubs_data.load_stubs_s(filepath, process_comments=True) stubs_data.guess_platform_vals() smisc = stubs_data.stubs_entry_misc if not 'ar_rom' in smisc: warn('No ROM region identified, giving up') return if not 'main_fw_code_end' in smisc: warn('Main firmware code end not identified, giving up') return if len(getMemoryBlocks()) > 1: warn('Program already has multiple memory blocks, giving up') mb_rom = getMemoryBlocks()[0] if mb_rom.getStart() != toAddr(smisc['ar_rom']['start_adr']): warn('Memory block start does not match ROM, giving up') return if not mb_rom.isInitialized(): warn('ROM block not initialized, giving up') return if mb_rom.getEnd() <= toAddr(smisc['main_fw_code_end']): warn( 'Already initialized? ROM block end <= main fw code end, giving up' ) return mbops.add_split('ROMDATA', smisc['main_fw_code_end'] + 1, w=False, x=False) make_romstarter_mblock(smisc) # if main firmware doesn't start at rom start, split if 'main_fw_start' in smisc and smisc['main_fw_start'] > smisc['ar_rom'][ 'start_adr']: mbops.add_split('ROMCODE', smisc['main_fw_start'], w=False, x=True) # ignored if not present ar_ramcode = smisc.get('ar_ramcode') ar_btcmcode = smisc.get('ar_btcmcode') ar_ramdata = smisc.get('ar_ramdata') ar_evec = smisc.get('ar_evec') ar_atcm = smisc.get('ar_atcm') mbops.add_stubs_ar(ar_ramdata, 'RAMDATA') mbops.add_stubs_ar(ar_ramcode, 'RAMCODE', x=True) mbops.add_stubs_ar(ar_btcmcode, 'BTCMCODE', x=True) mbops.add_stubs_ar(smisc.get('ar_itcm'), 'ITCM') mbops.add_stubs_ar(smisc.get('ar_uncached'), 'UNCACHED') mbops.add_stubs_ar(smisc.get('ar_dtcm'), 'DTCM') mbops.add_stubs_ar(smisc.get('ar_mmio'), 'MMIO', v=True) mbops.add_stubs_ar(smisc.get('ar_mmio_0xd'), 'MMIO', v=True) mbops.add_stubs_ar(smisc.get('ar_mmio_0xc1'), 'MMIO', v=True) mbops.add_stubs_ar(smisc.get('ar_mmio_0xc8'), 'MMIO', v=True) if smisc['digic'] >= 60: # RAM between ATCM and copied data mbops.add_uninit('RAM', 0x4000, 0x4000) # detected exception vector at address 0, add as initialized if ar_evec and ar_evec['start_adr'] == 0: mbops.add_stubs_ar(smisc.get('ar_evec'), 'EVEC') if ar_atcm and ar_atcm['start_adr'] == 0: mbops.add_uninit('ATCM', ar_evec['last_adr'] + 1, last_adr=ar_atcm['last_adr']) else: mbops.add_stubs_ar(smisc.get('ar_atcm'), 'ATCM') else: mbops.add_stubs_ar(smisc.get('ar_atcm'), 'ATCM') else: # RAM between ITCM and copied data mbops.add_uninit('RAM', 0x1000, 0x900) if ar_ramcode: # RAM between ram data and code (assumes code after data!) mbops.add_uninit('RAM', ar_ramdata['last_adr'] + 1, last_adr=ar_ramcode['start_adr'] - 1) # RAM from end of code to end of RAM mbops.add_uninit('RAM', ar_ramcode['last_adr'] + 1, last_adr=smisc['max_ram_addr']) else: # RAM from end of ram data to end of RAM mbops.add_uninit('RAM', ar_ramdata['last_adr'] + 1, last_adr=smisc['max_ram_addr']) if smisc['digic'] == 60: if ar_btcmcode and ar_btcmcode['start_adr'] == 0xbfe10800: # 0x800 before code mbops.add_uninit('BTCM', 0xbfe10000, 0x800) # from code end to 64k mbops.add_uninit('BTCM', ar_btcmcode['last_adr'] + 1, last_adr=0xbfe20000 - 1) elif smisc['digic'] == 70: # per https://chdk.setepontos.com/index.php?topic=11316.msg142197#msg142197 if ar_btcmcode and ar_btcmcode['start_adr'] == 0xdffc4900: # 0x4900 before code. TODO this is actually initialized, could create mapped mbops.add_uninit('BTCM', 0xdffc0000, 0x4900) # from code end to 256k mbops.add_uninit('BTCM', ar_btcmcode['last_adr'] + 1, last_adr=0xdfffffff) if g_options['include_zico']: for ardef in smisc['zico_blobs']: mbops.add_stubs_ar(ardef, 'ZICO') # set whole ROM read-only before splitting if not g_options['pretend']: mb_rom.setWrite(False) mbops.apply_ops()
def do_likely_func_start_list(l): for v in l: addr = toAddr(v[0]) r = is_likely_func_start(addr) if r != v[1]: warn('func_start fail %s %s != %s' % (addr, r, v[1]))