def close(self, flush_only=False): db_info.get(self.stage).flush_staticdb() print "captured %s writes" % self.writestable.nrows self.h5file.flush() if not flush_only: self.h5file.close()
def _stop(self, bp, ret): if self.controller.calculate_write_dst: self.writeinfo = self.emptywrite regs = {} eregs = [] for r in self.sregs: v = self.controller.get_reg_value(r, True) regs.update({r: v}) for r in self.eeregs: regs.update({r: self.controller.get_reg_value(r, True)}) eregs.append(v) if not self.destsubtract == "": regs.update({ self.destsubtract: self.controller.get_reg_value(self.destsubtract, True) }) needs_string = db_info.get(self.stage).is_longwrite_string( self.rangetype) str2 = None if needs_string: self.msg("getting string at 0x%x\n" % sum(eregs)) if self.isbaremetal: gdb.execute("mon gdb_sync") str2 = gdb.execute("print/s (char *) $%s" % eregs[0], to_string=True) str2 = str2.split("\"")[1] self.msg("string %s\n" % str2) (self.writeinfo['start'], self.writeinfo['end']) = db_info.get( self.stage).longwrites_calculate_dest_addrs( self.r, self.rangetype, regs, self.sregs, self.eeregs, str2) self.writeinfo['pc'] = self.writeaddr EndLongwriteBreak(self, self.stage) return False
def insert_write_breakpoints(self, stage): if any( map(lambda x: x == "WriteBreak", list(self.disabled_breakpoints))): return i = 0 n = db_info.get(stage).num_writes() self.gdb_print("%d write breakpoints\n" % n) for (pc, halt) in db_info.get(stage).write_info(): if halt is True: if self.isbaremetal: # check to see this address isn't in a skip range if db_info.get(stage).skip_pc(pc): # don't insert WriteBreak continue # halt should be false for write entries that match a longwrite writepc, # but check just in case if db_info.get(stage).is_pc_longwrite(pc): self.gdb_print( "write pc 0x%x is part of a longwrite, not adding breakpoint.\n" % pc) continue i = i + 1 WriteBreak(pc, self, stage) self.gdb_print("actually inserted %s of %s write breakpoints\n" % (i, n))
def catchall(self, event, rec, stage): timestamp = rec[1] if self.last_timestamp is None: self.last_timestamp = timestamp self.last_timestamp = timestamp i = 3 pid = -1 size = -1 addr = -1 pc = -1 lr = -1 cpsr = -1 for t, n in event.args: if n == 'pid': pid = rec[i] elif n == 'size': size = rec[i] elif n == 'addr': addr = rec[i] elif n == 'pc': pc = rec[i] elif n == 'lr': lr = rec[i] elif n == 'cpsr': cpsr = rec[i] i = i + 1 db_info.get(stage).add_trace_write_entry(timestamp, pid, size, addr, pc, lr, cpsr)
def populate_write_interval_table(self): substages = self._substage_numbers() if len(substages) < 1: logging.debug("No substages defined, not populating write interval table for %s" % (self.stage)) return intervals = self.calculate_intervals(substages) db_info.get(self.stage).write_trace_intervals(intervals, self.trace_intervals_table)
def histograminfo(self, outfile=None, csvfile=None): group = self.get_group() rangetable = group.writerange ret = '' if outfile: outfile = open(outfile, 'w') if csvfile: csvfile = open(csvfile, 'w') csvfile.write( "idx,pc,lrpc,numops,numbytes,substage,fn,lr,note,nudge\n") try: rs = rangetable.read_sorted('index') except ValueError: rangetable.cols.index.create_index(kind='full') rangetable.cols.index.reindex() rs = rangetable.read_sorted('index') i = 0 for rangerow in rs: (sdisasm, ssrc) = db_info.get(self.stage).disasm_and_src_from_pc( rangerow['pc']) pcfname = '' lrfname = '' try: pcfname = next( db_info.get(self.stage).func_at_addr(rangerow['pc'])) except StopIteration: pass try: lrfname = next( db_info.get(self.stage).func_at_addr(rangerow['lr'])) except StopIteration: pass r = "pc=%x/[%x] (%s) lr=%x (%s) [%x-%x] (%d) %d times -- %s -- %s\n" % \ (rangerow['relocatedpc'], rangerow['pc'], pcfname, rangerow['lr'], lrfname, rangerow['destlo'], rangerow['desthi'], rangerow['byteswritten'], rangerow['numops'], sdisasm, ssrc) n = rangerow['byteswritten'] if n < 0: n = n * -1 r2 = "%s,0x%x,0x%x,%s,%s,%s,%s,%s,,\n" % ( i, rangerow['pc'], rangerow['lr'], rangerow['numops'], n, rangerow['substage'], pcfname, lrfname) if outfile: outfile.write(r) if csvfile: if rangerow['numops'] > 1: csvfile.write(r2) else: ret = ret + r i += 1 if outfile: outfile.close() if csvfile: csvfile.close() return ret
def do(self): global db_written if db_written: return db_info.get(self.stage).flush_tracedb() global start db_info.get(self.stage).flush_tracedb() stop = time.time() gdb.write(".. finished in %f minutes\n" % ((stop-start)/60), gdb.STDOUT) db_written = True
def lookup_symbol_interval(self, name, num): (startaddr, endaddr) = db_info.get(self.stage).mmap_var_loc(name) reloc_names = db_info.get(self.stage).reloc_names_in_substage(num) varloc = intervaltree.Interval(startaddr, endaddr) for (rname, rbegin, rsize, roffset) in db_info.get( self.stage).reloc_info_by_cardinal(reloc_names): relrange = intervaltree.Interval(rbegin, rbegin + rsize) if relrange.contains_interval(varloc): offset = roffset varloc = intervaltree.Interval(varloc.begin + offset, varloc.end + offset) return varloc
def do(self): db_info.get(self.stage).add_trace_write_entry(self.time, self.pid, self.size, self.dest, self.pc, self.lr, self.cpsr, self.step, self.num) if self.size < 0: end = self.dest start = self.dest + self.size else: start = self.dest end = self.dest + self.size db_info.get(self.stage).update_trace_writes('', self.pc, start, end, self.stage, self.origpc, self.num)
def insert_stageend_breakpoints(self, stage): s_info = self._stages[stage.stagename] end = s_info.stoppoint if end: s_info.endbreaks.append(StageEndBreak(end, self, stage, True)) for (addr, line, success) in db_info.get(stage).stage_exits(): s_info.endbreaks.append(StageEndBreak(addr, self, stage, success))
def __init__(self, fn, d, num, stage, prevstage, mmap_info): self.fn = fn self.num = num self.substage_type = get_value(d, 'substage_type').lower() prev_regions = prevstage.defined_regions if prevstage else set() self._new_regions = get_value(d, 'new_regions') self.new_regions = set() self.defined_regions = set(prev_regions) self._reclassified_regions = get_value(d, 'reclassified_regions') self.reclassified_regions = set() self._undefined_regions = get_value(d, 'undefined_regions') self.undefined_regions = set() self.allowed_symbols = get_value(d, 'allowed_symbols') self.reclassified_regions = set() self.comments = get_value(d, 'comments') self.writable_regions = set() stack = get_value(d, 'stack') prevstack = prevstage.stack if prevstage else None self.stack = stack if stack else prevstack self._setup_region_info(mmap_info.regions if mmap_info else {}, prev_regions) # convert from set to list for i in ['writable', 'reclassified', 'defined', 'new', 'undefined']: n = i + '_regions' s = getattr(self, n) setattr(self, n, list(s)) self.new_reloc = False if self.is_cooking_substage() or self.is_patching_substage(): # see if listed in reloc table if db_info.get(stage).name_in_relocs_table(self.fn): self.new_reloc = True self.applied_relocs = [] if prevstage is None else prevstage.applied_relocs if prevstage and prevstage.new_reloc: self.applied_relocs.append(prevstage.fn)
def check_trace(self, table): print "Checking policy at (%s,%s)" % (self.substage_file_path, self.mmap_file) violation = False snums = self._substage_numbers() for n in snums: allowed_writes = self.allowed_writes(n) for r in db_info.get(self.stage).get_substage_writes(n): size = r['reportedsize'] if size < 0: end = r['dest'] start = end + size # + 1 else: start = r['dest'] end = start + size # - 1 if start == end: res = allowed_writes.search(start) else: res = allowed_writes.search(start, end) if not len(res) == 1: write = r['relocatedpc'] print "Substage %d: invalid write by %x to (%x,%x)" % ( n, write, start, end) violation = True if not violation: print "Policy was not violated :)" return True else: return False
def check_trace(self, table): violation = False snums = self._substage_numbers() logging.info("---- CHECKING TRACE FOR WRITE VIOLATIONS -----") for n in snums: allowed_writes = self.allowed_writes(n) for r in db_info.get(self.stage).get_substage_writes(n): size = long(r['reportedsize']) if size < 0: end = long(r['dest']) start = end + size # + 1 else: start = long(r['dest']) end = start + size # - 1 if start == end: res = allowed_writes.search(start) else: res = allowed_writes.search(start, end) if not len(res) == 1: write = long(r['relocatedpc']) logging.info("Substage %d: invalid write by pc 0x%x to addr (%x,%x)" % (n, write, start, end)) violation = True if violation: # print "Policy was not violated :)" logging.info("Policy VIOLATED!!!1one :(") logging.info("-------------------------------------------") return True else: logging.info("Policy not violated") logging.info("-------------------------------------------") return False
def _stop(self, bp, ret): cont = self.controller if cont.calculate_write_dst: self.writeinfo = self.emptywrite pc = cont.get_reg_value('pc', True) inspc = pc - self.relocated cpsr = cont.get_reg_value("cpsr", True) thumb = cont.ia.is_thumb(cpsr) i = cont.get_instr_value(pc, thumb) ins = cont.ia.disasm(i, thumb, inspc, True) row = db_info.get(self.stage).pc_writes_info(inspc) size = row['writesize'] needed_regs = [row['reg0'], row['reg1'], row['reg2'], row['reg3']] regs = [] for r in filter(lambda x: len(x) > 0, needed_regs): regs.append(cont.get_reg_value(r, True)) dst = cont.ia.calculate_store_offset(ins, regs) if size < 0: # (ie. push instruction) end = dst start = dst + size else: start = dst end = dst + size self.writeinfo = { 'pc': pc, 'start': start, 'end': end, 'cpsr': cpsr, 'thumb': thumb, 'i': i, 'ins': ins, } return False
def check_trace(self, table): violation = False snums = self._substage_numbers() print "---- CHECKING TRACE FOR WRITE VIOLATIONS -----" for n in snums: allowed_writes = self.allowed_writes(n) for r in db_info.get(self.stage).get_substage_writes(n): size = r['reportedsize'] if size < 0: end = r['dest'] start = end + size # + 1 else: start = r['dest'] end = start + size # - 1 if start == end: res = allowed_writes.search(start) else: res = allowed_writes.search(start, end) if not len(res) == 1: write = r['relocatedpc'] print "Substage %d: invalid write by %x to (%x,%x)" % ( n, write, start, end) violation = True #exit(0) if not violation: print "Policy was not violated :)" print "-------------------------------------------" return True else: print "-------------------------------------------" return False
def process(events, log, analyzer, read_header, stage): """Invoke an analyzer on each event in a log.""" if isinstance(events, str): events = _read_events(open(events, 'r')) if isinstance(log, str): log = open(log, 'rb') if read_header: read_trace_header(log) dropped_event = Event.build("Dropped_Event(uint64_t num_events_dropped)") edict = {dropped_event_id: dropped_event} for num, event in enumerate(events): edict[num] = event def build_fn(analyzer, event): if isinstance(event, str): return analyzer.catchall fn = getattr(analyzer, event.name, None) if fn is None: return analyzer.catchall event_argcount = len(event.args) fn_argcount = len(inspect.getargspec(fn)[0]) - 1 if fn_argcount == event_argcount + 1: # Include timestamp as first argument return lambda _, rec: fn(*( (rec[1:2], ) + rec[3:3 + event_argcount])) elif fn_argcount == event_argcount + 2: # Include timestamp and pid return lambda _, rec: fn(*rec[1:3 + event_argcount]) else: # Just arguments, no timestamp or pid return lambda _, rec: fn(*rec[3:3 + event_argcount]) analyzer.begin() fn_cache = {} db_info.create(stage, "tracedb") for rec in read_trace_records(edict, log): event_num = rec[0] event = edict[event_num] if event_num not in fn_cache: fn_cache[event_num] = build_fn(analyzer, event) fn_cache[event_num](event, rec, stage) db_info.get(stage).flush_tracedb()
def populate_policy_table(self, ss_info, mmap_info, policy_table): regions = list(mmap_info.regions.iterkeys()) if policy_table.nrows > 0: self.mmap_created = False return policy_row = policy_table.row for s in ss_info.substages.itervalues(): for r in mmap_info.regions.itervalues(): policy_row['default_perms'] = getattr(perms, r.default_perms) policy_row['short_name'] = r.short_name policy_row['region_type'] = getattr(region_types, r.type_at_substage(s.num)) policy_row['substagenum'] = s.num policy_row['new'] = r.short_name in s.new_regions policy_row['undefined'] = r.short_name in s.undefined_regions policy_row['defined'] = r.short_name in s.defined_regions policy_row['writable'] = r.short_name in s.writable_regions policy_row[ 'reclassified'] = r.short_name in s.reclassified_regions policy_row['allowed_symbol'] = False policy_row['do_print'] = True if r.parent and r.parent._csv: policy_row['do_print'] = False policy_row['symbol_name'] = '' policy_row['symbol_elf_name'] = '' policy_row.append() for v in s.allowed_symbols: pat = "^(%s)(.[\d]{5})?$" % v found = False for r in db_info.get(self.stage).symbol_names_with(v): match = re.match(pat, r) if match is None: continue else: rname = self.region_name_from_symbol(v) policy_row['default_perms'] = getattr(perms, 'rwx') policy_row['short_name'] = rname policy_row['symbol_elf_name'] = r policy_row['symbol_name'] = v policy_row['region_type'] = getattr( region_types, 'symbol') policy_row['substagenum'] = s.num policy_row['new'] = False policy_row['defined'] = False policy_row['undefined'] = False policy_row['writable'] = True policy_row['reclassified'] = False policy_row['allowed_symbol'] = True policy_row['do_print'] = True policy_row.append() found = True break if not found: raise Exception("could not find symbol named %s" % v) policy_table.flush() policy_table.cols.substagenum.reindex() policy_table.cols.short_name.reindex() policy_table.flush()
def calculate_trace_intervals(self, substages, tracename): fns = self._substage_names() num = 0 substage_entries = {num: self.fun_info(fns[num + 1]) for num in range(0, len(fns) - 1)} intervals = db_info.get(self.stage).write_interval_info(tracename, substages, substage_entries) for i in intervals.iteritems(): i.merge_overlaps() return intervals
def print_dsts_info(self): self.flush_table() num_writes = db_info.get(self.stage).num_writes() num_framac_writes = sum([len(pytable_utils.get_rows(t, "dst_not_in_ram == True")) for t in self.tables.itervalues()]) print "%d of %d writes exclusively write "\ "to register memory" % (num_framac_writes, num_writes) for t in self.tables.itervalues(): for r in t.iterrows(): print "%s (%x) -> (%x,%x). substage: %s" % \ (r['line'], r['writepc'], r['dstlo'], r['dsthi'], r['substage'])
def __init__(self, start, end, inplace, table): self.stage = table.stage self.table = table self.inplace = inplace self.valid = False self.start = start self.end = end self.thumb = self.table.thumbranges.overlaps_point(self.start) self.info = LongWriteInfo(self.stage.elf, self.start, self.end, self.thumb) self.info.calculate_info() ins = self.table.ia.disasm( b"%s" % self.info.write_ins["bytes"].decode("hex"), self.thumb, self.info.write_ins["offset"]) self.write_size = self.table.ia.calculate_store_size(ins) self.breakaddr = self.info.start_ins_addr self.writeaddr = self.info.write_ins_addr self.contaddr = self.info.finish_ins_addr writes = self.table.writestable.where( "(0x%x == pclo) & (0x%x == pchi)" % (utils.addr_lo(self.writeaddr), utils.addr_hi(self.writeaddr))) try: write = next(writes) except Exception as e: print e print "Longwrite not found at %x (%s)" % (self.writeaddr, self.__dict__) return self.valid = True self.writesize = write['writesize'] r2.get(self.stage.elf, "s 0x%x" % self.writeaddr) if self.thumb: r2.get(self.stage.elf, "e asm.bits=16") r2.gets(self.stage.elf, "ahb 16") else: r2.get(self.stage.elf, "e asm.bits=32") r2.gets(self.stage.elf, "ahb 32") r2.get(self.stage.elf, "pd 1") i = r2.get(self.stage.elf, "pdj 1")[0] self.value = b"%s" % i["bytes"] self.disasm = i["disasm"] write['halt'] = False write.update() self.funname = db_info.get(self.stage).addr2functionname( self.writeaddr) self.instr = self.table.ia.disasm(self.value, self.thumb, self.writeaddr) self.table.writestable.flush()
def _relocated(regname, fullname): r = allregions[regname] ret = s rend = fullname.rsplit(".", 1)[1] cardinalres = re.match("([\d])+_relocated", rend) cardinal = cardinalres.group(1) relocindex = re.sub("[._relocated]+", "", rend) if r.addresses_resolved: start = min(r.addresses).begin end = max(r.addresses).end (offset, mod) = db_info.get(self.stage).reloc_offset_and_mod_from_cardinal(relocindex) ret = intervaltree.Interval((start + offset) % mod, (end + offset) % mod) return ret
def uboot_mux(self, dstinfo): # hack path = dstinfo.path cmd = 'grep -n "MUX_BEAGLE();" %s' % path lineno = Main.shell.run_cmd(cmd, catcherror=True) if lineno: # so sorry, this is a hack to deal with the annoying amount of writes # squished into a u-boot macro lineno = int(lineno.split(":")[0]) if path.endswith("board/ti/beagle/beagle.c") and lineno == dstinfo.lineno: dstinfo.pc = self._find_mux_pc(v.begin) else: dstinfo.pc = db_info.get(self.stage).get_write_pc_or_zero_from_dstinfo(dstinfo)
def calculate_framac_intervals(self, substages): intervals = {n: intervaltree.IntervalTree() for n in substages} for num in substages: for r in pytable_utils.get_rows(self.trace_intervals_table, 'substagenum == %s' % num): # lookup writes performed by this function f = r['functionname'] (lopc, hipc) = self.fun_info(f) res = db_info.get(self.stage).write_interval_info( tracename, lopc, hipc) intervals[num] += intervaltree.IntervalTree( [intervaltree.Interval(r[0], r[1]) for r in res]) return intervals
def update_db(self): if self.results: db_info.create(self.stage, "tracedb") results = [r for r in self.results.itervalues()] print "have %d results" % len(results) print "adding dst entries" for r in results: db_info.get(self.stage).add_range_dsts_entry(r) print '-----------' # db_info.get(self.stage).print_range_dsts_info() db_info.get(self.stage).consolidate_trace_write_table() db_info.get(self.stage).flush_tracedb()
def addr2disasmobjdump(addr, sz, stage, thumb=True, debug=False): old = r2.gets(stage.elf, "s") r2.gets(stage.elf, "s 0x%x" % addr) if thumb: # force r2 to use the correct instruction size. sigh. r2.gets(stage.elf, "ahb 16") r2.gets(stage.elf, "e asm.bits=16") else: r2.gets(stage.elf, "ahb 32") r2.gets(stage.elf, "e asm.bits=32") r2.get(stage.elf, "pd 1") i = r2.get(stage.elf, "pdj 1")[0] if "disasm" in i or u"invalid" == i["type"] or u"invalid" == i["disasm"]: r2.get(stage.elf, "s %s" % old) return (None, None, None) fn = db_info.get(stage).addr2functionname(addr) r2.get(stage.elf, "s %s" % old) return (i['bytes'], i['disasm'], fn)
def finalize_hook(self, args): substages = False for s in self.controller._stages.itervalues(): if s.substages: substages = True break if not substages: self.controller.gdb_print( 'No substages to set, do not know what to enforce', self.name) return global allowed_writes for s in [ _s for _s in self.controller._stages.itervalues() if _s.stage in self.controller.stage_order ]: name = s.stage.stagename # policy = self.controller.policy_file ss = self.controller._stages[name].substages_entrypoints i = db_info.get(s.stage) allowed_writes[name] = {} for n in range(0, len(ss)): allowed_writes[name][n] = i.allowed_substage_writes(n)
def add_dsts_entry(self, dstinfo): num = dstinfo.substage if num not in self.tables.iterkeys(): self._init_table(num) r = self.tables[num].row for v in dstinfo.values: r['dstlo'] = v.begin r['dsthi'] = v.end r['dst_not_in_ram'] = self._addr_inter_is_not_ram(v) r['substage'] = dstinfo.substage line = dstinfo.key() r['line'] = line r['lvalue'] = dstinfo.lvalue if not dstinfo.pc: # hack path = dstinfo.path cmd = 'grep -n "MUX_BEAGLE();" %s' % path lineno = Main.shell.run_cmd(cmd, catcherror=True) if lineno: lineno = int(lineno.split(":")[0]) if path.endswith("board/ti/beagle/beagle.c" ) and lineno == dstinfo.lineno: dstinfo.pc = self._find_mux_pc(v.begin) else: dstinfo.pc = db_info.get( self.stage).get_write_pc_or_zero_from_dstinfo(dstinfo) # figure out which write instruction #lineno = int(os.system("grep %s %s/%s" % ( , root, path)) if dstinfo.pc == 0: print "cannot resove just one write instruction from %s" % dstinfo.__dict__ continue r['writepc'] = dstinfo.pc r['origpc'] = dstinfo.origpc if dstinfo.origpc else r['writepc'] r.append()
def insert_longwrites_breakpoints(self, stage): if any(map(lambda x: x == "LongwriteBreak", self.disabled_breakpoints)): return for r in db_info.get(stage).longwrites_info(): LongwriteBreak(self, r, stage)
def insert_reloc_breakpoints(self, stage): if any(map(lambda x: x == "RelocBreak", self.disabled_breakpoints)): return for r in db_info.get(stage).reloc_info(): RelocBreak(self, stage, r)
def fun_info(self, fun): res = db_info.get(self.stage).function_locations(fun) if len(res) == 0: return utils.get_symbol_location_start_end(fun, self.stage) else: return res[0]