def main(APP): conv_imm = 0 unconv_imm = 0 for area in aspace.get_areas(): if not "X" in area[engine.PROPS].get("access", ""): continue #print(area[:-2]) last_inst = None for i in inst_in_area(area): if last_inst and i.disasm in ( "goto $a0", "call $a0") and last_inst.disasm.startswith("$a0 = "): if last_inst[2].type == idaapi.o_imm: if not APP.is_ui: print(last_inst) print(i) target_addr = last_inst[2].get_addr() # Change 1 if not APP.aspace.is_arg_offset(last_inst.ea, 2): APP.aspace.make_arg_offset(last_inst.ea, 2, target_addr) conv_imm += 1 else: unconv_imm += 1 # Change 2 # Note: side effect of this is that of sequence # $a0 = sym # call $a0 # "$a0 = sym" will be marked as having "c" (call) xref to sym, # whereas before this plugin run, the same line had "o" xref. # More formally correct approach would be to make "call $a0" # line to have "c" xref, but this would lead to doubling size of # xref list. So, this entire situation is considered a feature, not # a bug, and indeed what a user wants (and 2 instructions above # can be considered a single compound instruction anyway). idaapi.ua_add_cref( 0, target_addr, idaapi.fl_CN if i.disasm[0] == "c" else idaapi.fl_JN) last_inst = i engine.analyze(lambda c: print(c)) if not APP.is_ui: print("Immediates converted to offsets: %d, already converted: %d" % (conv_imm, unconv_imm)) print("Done, press Enter") input()
def main(APP): conv_imm = 0 unconv_imm = 0 for area in aspace.get_areas(): if not "X" in area[engine.PROPS].get("access", ""): continue #print(area[:-2]) last_inst = None for i in inst_in_area(area): if last_inst and i.disasm in ("goto $a0", "call $a0") and last_inst.disasm.startswith("$a0 = "): if last_inst[2].type == idaapi.o_imm: if not APP.is_ui: print(last_inst) print(i) target_addr = last_inst[2].get_addr() # Change 1 if not APP.aspace.is_arg_offset(last_inst.ea, 2): APP.aspace.make_arg_offset(last_inst.ea, 2, target_addr) conv_imm += 1 else: unconv_imm += 1 # Change 2 # Note: side effect of this is that of sequence # $a0 = sym # call $a0 # "$a0 = sym" will be marked as having "c" (call) xref to sym, # whereas before this plugin run, the same line had "o" xref. # More formally correct approach would be to make "call $a0" # line to have "c" xref, but this would lead to doubling size of # xref list. So, this entire situation is considered a feature, not # a bug, and indeed what a user wants (and 2 instructions above # can be considered a single compound instruction anyway). idaapi.ua_add_cref(0, target_addr, idaapi.fl_CN if i.disasm[0] == "c" else idaapi.fl_JN) last_inst = i engine.analyze(lambda c: print(c)) if not APP.is_ui: print("Immediates converted to offsets: %d, already converted: %d" % (conv_imm, unconv_imm)) print("Done, press Enter") input()
def handle_key_unprotected(self, key): if key == editor.KEY_ENTER: line = self.get_cur_line() log.info("Enter pressed: %s" % line) op_no = self.cur_operand_no(line) self.show_status("Enter pressed: %s, %s" % (self.col, op_no)) if isinstance(line, engine.DisasmObj): to_addr = None if op_no >= 0: o = line[op_no] to_addr = o.get_addr() if to_addr is None: o = line.get_operand_addr() if o: to_addr = o.get_addr() self.goto_addr(to_addr, from_addr=line.ea) elif key == editor.KEY_ESC: if self.addr_stack: self.show_status("Returning") self.goto_addr(self.addr_stack.pop()) elif key == b"q": return editor.KEY_QUIT elif key == b"c": addr = self.cur_addr() self.show_status("Analyzing at %x" % addr) engine.add_entrypoint(addr, False) engine.analyze(self.analyze_status) self.update_model() elif key == b"d": addr = self.cur_addr() fl = self.model.AS.get_flags(addr) if fl not in (self.model.AS.DATA, self.model.AS.UNK): self.show_status("Undefine first") return if fl == self.model.AS.UNK: self.model.AS.set_flags(addr, 1, self.model.AS.DATA, self.model.AS.DATA_CONT) else: sz = self.model.AS.get_unit_size(addr) self.model.undefine_unit(addr) sz *= 2 if sz > 4: sz = 1 self.model.AS.set_flags(addr, sz, self.model.AS.DATA, self.model.AS.DATA_CONT) self.update_model() elif key == b"a": addr = self.cur_addr() fl = self.model.AS.get_flags(addr) if fl != self.model.AS.UNK: self.show_status("Undefine first") return sz = 0 label = "s_" while True: b = self.model.AS.get_byte(addr) fl = self.model.AS.get_flags(addr) if not (0x20 <= b <= 0x7e or b in (0x0a, 0x0d)): if b == 0: sz += 1 break if fl != self.model.AS.UNK: break c = chr(b) if c < '0' or c in string.punctuation: c = '_' label += c addr += 1 sz += 1 if sz > 0: self.model.AS.set_flags(self.cur_addr(), sz, self.model.AS.STR, self.model.AS.DATA_CONT) self.model.AS.make_unique_label(self.cur_addr(), label) self.update_model() elif key == b"u": addr = self.cur_addr() self.model.undefine_unit(addr) self.update_model() elif key == b"o": addr = self.cur_addr() line = self.get_cur_line() o = line.get_operand_addr() if not o: self.show_status("Cannot convert operand to offset") return if o.type != idaapi.o_imm or not self.model.AS.is_valid_addr(o.get_addr()): self.show_status("Cannot convert operand to offset: #%s: %s" % (o.n, o.type)) return if self.model.AS.get_arg_prop(addr, o.n, "type") == idaapi.o_mem: self.model.AS.set_arg_prop(addr, o.n, "type", idaapi.o_imm) self.model.AS.del_xref(addr, o.get_addr(), idaapi.dr_O) else: self.model.AS.make_arg_offset(addr, o.n, o.get_addr()) self.update_model(True) elif key == b";": addr = self.cur_addr() comment = self.model.AS.get_comment(addr) or "" res = self.dialog_edit_line(line=comment, width=60) if res: self.model.AS.set_comment(addr, res) self.update_screen() elif key == b"n": addr = self.cur_addr() label = self.model.AS.get_label(addr) def_label = self.model.AS.get_default_label(addr) s = label or def_label while True: res = self.dialog_edit_line(line=s) if not res: break if res == def_label: res = addr else: if self.model.AS.label_exists(res): s = res self.show_status("Duplicate label") continue self.model.AS.set_label(addr, res) if not label: # If it's new label, we need to add it to model self.update_model() return break self.update_screen() elif key == b"g": F = npyscreen.FormBaseNew(name='Go to', lines=6, columns=40, show_atx=4, show_aty=4) e = F.add(LabelEntry, name="Labels") e.set_choices(self.model.AS.get_label_list()) def h_enter_key(input): if not e.value: # Hitting Enter with empty text entry opens autocomplete dropbox e.auto_complete(input) else: F.exit_editing() e.add_handlers({curses.ascii.CR: h_enter_key}) F.add(npyscreen.FixedText, value="Press Tab to auto-complete", editable=False) F.edit() self.update_screen() if e.value: if '0' <= e.value[0] <= '9': res = int(e.value, 0) else: res = self.model.AS.resolve_label(e.value) self.goto_addr(res, from_addr=self.cur_addr()) elif key == editor.KEY_F1: help.help(self) self.update_screen() elif key == b"S": save_state(project_dir) self.show_status("Saved.") elif key == b"\x11": # ^Q F = npyscreen.Popup(name='Problems list', lines=18) class IssueList(npyscreen.MultiLine): def display_value(self, vl): return "%08x %s" % vl lw = F.add(IssueList, name="Problems") #lw.return_exit = True lw.values = self.model.AS.get_issues() lw.add_handlers({curses.ascii.CR: lambda key: (lw.h_select_exit(key), F.exit_editing(), 1)}) F.edit() self.update_screen() if lw.value is not None: val = lw.values[lw.value][0] self.goto_addr(val, from_addr=self.cur_addr()) elif key == b"i": off, area = self.model.AS.addr2area(self.cur_addr()) props = area[engine.PROPS] percent = 100 * off / (area[engine.END] - area[engine.START] + 1) func = self.model.AS.lookup_func(self.cur_addr()) func = self.model.AS.get_label(func.start) if func else None self.show_status("Area: 0x%x %s (%s): %.1f%%, func: %s" % ( area[engine.START], props.get("name", "noname"), props["access"], percent, func )) elif key == b"W": class TextSaveModel: def __init__(self, f, ctrl): self.f = f self.ctrl = ctrl self.cnt = 0 def add_line(self, addr, line): line = ("%08x " % addr) + line.indent + line.render() + "\n" self.f.write(line) if self.cnt % 256 == 0: self.ctrl.show_status("Writing: 0x%x" % addr) self.cnt += 1 out_fname = "out.lst" with open(out_fname, "w") as f: engine.render_partial(TextSaveModel(f, self), 0, 0, 10000000) self.show_status("Disassembly listing written: " + out_fname) elif key in (b"/", b"?"): # "/" and Shift+"/" class FoundException(Exception): pass class TextSearchModel: def __init__(self, substr, ctrl): self.search = substr self.ctrl = ctrl self.cnt = 0 def add_line(self, addr, line): line = line.render() if self.search in line: raise FoundException(addr) if self.cnt % 256 == 0: self.ctrl.show_status("Searching: 0x%x" % addr) self.cnt += 1 if key == b"/": F = npyscreen.FormBaseNew(name='Text Search', lines=5, columns=40, show_atx=4, show_aty=4) e = F.add(npyscreen.TitleText, name="Search for:") e.entry_widget.add_handlers({curses.ascii.CR: lambda k: F.exit_editing()}) F.edit() self.update_screen() self.search_str = e.value addr = self.cur_addr() else: addr = self.next_addr() try: engine.render_from(TextSearchModel(self.search_str, self), addr, 10000000) except FoundException as res: self.goto_addr(res.args[0], from_addr=self.cur_addr()) else: self.show_status("Not found: " + self.search_str) else: self.show_status("Unbound key: " + repr(key))
if show_bytes: engine.DisasmObj.LEADER_SIZE += show_bytes * 2 + 1 # Strip suffix if any from def filename project_dir = project_name + ".scratchabit" if os.path.exists(project_dir + "/project.labels"): load_state(project_dir) else: for label, addr in ENTRYPOINTS: if engine.ADDRESS_SPACE.is_exec(addr): engine.add_entrypoint(addr) engine.ADDRESS_SPACE.make_unique_label(addr, label) def _progress(cnt): sys.stdout.write("Performing initial analysis... %d\r" % cnt) engine.analyze(_progress) print() #engine.print_address_map() if ENTRYPOINTS: show_addr = ENTRYPOINTS[0][1] else: show_addr = engine.ADDRESS_SPACE.min_addr() t = time.time() #_model = engine.render() _model = engine.render_partial_around(show_addr, 0, HEIGHT * 2) print("Rendering time: %fs" % (time.time() - t)) #print(_model.lines()) #sys.exit()
def handle_key(self, key): if key == editor.KEY_ENTER: line = self.get_cur_line() log.info("Enter pressed: %s" % line) op_no = self.cur_operand_no(line) self.show_status("Enter pressed: %s, %s" % (self.col, op_no)) if isinstance(line, engine.DisasmObj): to_addr = None if op_no >= 0: o = line[op_no] to_addr = o.get_addr() if to_addr is None: o = line.get_operand_addr() if o: to_addr = o.get_addr() self.goto_addr(to_addr, from_addr=line.ea) elif key == editor.KEY_ESC: if self.addr_stack: self.show_status("Returning") self.goto_addr(self.addr_stack.pop()) elif key == b"q": return editor.KEY_QUIT elif key == b"c": addr = self.cur_addr() self.show_status("Analyzing at %x" % addr) engine.add_entrypoint(addr) engine.analyze(self.analyze_status) self.update_model() elif key == b"d": addr = self.cur_addr() fl = self.model.AS.get_flags(addr) if fl not in (self.model.AS.DATA, self.model.AS.UNK): self.show_status("Undefine first") return if fl == self.model.AS.UNK: self.model.AS.set_flags(addr, 1, self.model.AS.DATA, self.model.AS.DATA_CONT) else: sz = self.model.AS.get_unit_size(addr) self.model.undefine(addr) sz *= 2 if sz > 4: sz = 1 self.model.AS.set_flags(addr, sz, self.model.AS.DATA, self.model.AS.DATA_CONT) self.update_model() elif key == b"a": addr = self.cur_addr() fl = self.model.AS.get_flags(addr) if fl != self.model.AS.UNK: self.show_status("Undefine first") return sz = 0 label = "s_" while True: b = self.model.AS.get_byte(addr) fl = self.model.AS.get_flags(addr) if not (0x20 <= b <= 0x7e or b in (0x0a, 0x0d)): if b == 0: sz += 1 break if fl != self.model.AS.UNK: break c = chr(b) if c < '0' or c in string.punctuation: c = '_' label += c addr += 1 sz += 1 if sz > 0: self.model.AS.set_flags(self.cur_addr(), sz, self.model.AS.STR, self.model.AS.DATA_CONT) self.model.AS.make_unique_label(self.cur_addr(), label) self.update_model() elif key == b"u": addr = self.cur_addr() self.model.undefine(addr) self.update_model() elif key == b"o": addr = self.cur_addr() line = self.get_cur_line() o = line.get_operand_addr() if not o: self.show_status("Cannot convert operand to offset") return if o.type != idaapi.o_imm or not self.model.AS.is_valid_addr(o.get_addr()): self.show_status("Cannot convert operand to offset: #%s: %s" % (o.n, o.type)) return if self.model.AS.get_arg_prop(addr, o.n, "type") == idaapi.o_mem: self.model.AS.set_arg_prop(addr, o.n, "type", idaapi.o_imm) self.model.AS.del_xref(addr, o.get_addr(), idaapi.dr_O) else: self.model.AS.set_arg_prop(addr, o.n, "type", idaapi.o_mem) label = self.model.AS.get_label(o.get_addr()) if not label: self.model.AS.make_auto_label(o.get_addr()) self.model.AS.add_xref(addr, o.get_addr(), idaapi.dr_O) self.update_model(True) elif key == b";": addr = self.cur_addr() comment = self.model.AS.get_comment(addr) or "" res = self.dialog_edit_line(line=comment, width=60) if res: self.model.AS.set_comment(addr, res) self.update_screen() elif key == b"n": addr = self.cur_addr() label = self.model.AS.get_label(addr) def_label = self.model.AS.get_default_label(addr) s = label or def_label while True: res = self.dialog_edit_line(line=s) if not res: break if res == def_label: res = addr else: if self.model.AS.label_exists(res): s = res self.show_status("Duplicate label") continue self.model.AS.set_label(addr, res) if not label: # If it's new label, we need to add it to model self.update_model() return break self.update_screen() elif key == b"g": F = npyscreen.FormBaseNew(name='Go to', lines=6, columns=40, show_atx=4, show_aty=4) e = F.add(LabelEntry, name="Labels") e.set_choices(self.model.AS.get_label_list()) def h_enter_key(input): if not e.value: # Hitting Enter with empty text entry opens autocomplete dropbox e.auto_complete(input) else: F.exit_editing() e.add_handlers({curses.ascii.CR: h_enter_key}) F.add(npyscreen.FixedText, value="Press Tab to auto-complete", editable=False) F.edit() self.update_screen() if e.value: if '0' <= e.value[0] <= '9': res = int(e.value, 0) else: res = self.model.AS.resolve_label(e.value) self.goto_addr(res, from_addr=self.cur_addr()) elif key == editor.KEY_F1: help.help(self) self.update_screen() elif key == b"S": save_state(project_dir) self.show_status("Saved.")
engine.DisasmObj.LEADER_SIZE = 8 + 1 if show_bytes: engine.DisasmObj.LEADER_SIZE += show_bytes * 2 + 1 # Strip suffix if any from def filename project_name = sys.argv[1].rsplit(".", 1)[0] project_dir = project_name + ".scratchabit" if os.path.exists(project_dir + "/project.labels"): load_state(project_dir) else: for label, addr in ENTRYPOINTS: engine.add_entrypoint(addr) engine.ADDRESS_SPACE.set_label(addr, label) engine.analyze() #engine.print_address_map() if ENTRYPOINTS: show_addr = ENTRYPOINTS[0][1] else: show_addr = engine.ADDRESS_SPACE.min_addr() t = time.time() #_model = engine.render() _model = engine.render_partial_around(show_addr, 0, HEIGHT * 2) print("Rendering time: %fs" % (time.time() - t)) #print(_model.lines()) #sys.exit()
def handle_key_unprotected(self, key): if key == editor.KEY_ENTER: line = self.get_cur_line() log.info("Enter pressed: %s" % line) op_no = self.cur_operand_no(line) self.show_status("Enter pressed: %s, %s" % (self.col, op_no)) to_addr = None # No longer try to jump only to addresses in args, parse # textual representation below if False and isinstance(line, engine.DisasmObj): if op_no >= 0: o = line[op_no] to_addr = o.get_addr() if to_addr is None: o = line.get_operand_addr() if o: to_addr = o.get_addr() if to_addr is None: pos = self.col - line.LEADER_SIZE - len(line.indent) word = utils.get_word_at_pos(line.cache, pos) if word: if word[0].isdigit(): to_addr = int(word, 0) else: to_addr = self.model.AS.resolve_label(word) if to_addr is None: self.show_status("Unknown address: %s" % word) return self.goto_addr(to_addr, from_addr=line.ea) elif key == editor.KEY_ESC: if self.addr_stack: self.show_status("Returning") self.goto_addr(self.addr_stack.pop()) elif key == b"q": return editor.KEY_QUIT elif key == b"c": addr = self.cur_addr() self.show_status("Analyzing at %x" % addr) engine.add_entrypoint(addr, False) engine.analyze(self.analyze_status) self.update_model() elif key == b"d": addr = self.cur_addr() fl = self.model.AS.get_flags(addr) if fl not in (self.model.AS.DATA, self.model.AS.UNK): self.show_status("Undefine first") return if fl == self.model.AS.UNK: self.model.AS.set_flags(addr, 1, self.model.AS.DATA, self.model.AS.DATA_CONT) else: sz = self.model.AS.get_unit_size(addr) self.model.undefine_unit(addr) sz *= 2 if sz > 4: sz = 1 self.model.AS.set_flags(addr, sz, self.model.AS.DATA, self.model.AS.DATA_CONT) self.update_model() elif key == b"a": addr = self.cur_addr() fl = self.model.AS.get_flags(addr) if fl != self.model.AS.UNK: self.show_status("Undefine first") return sz = 0 label = "s_" while True: b = self.model.AS.get_byte(addr) fl = self.model.AS.get_flags(addr) if not (0x20 <= b <= 0x7e or b in (0x0a, 0x0d)): if b == 0: sz += 1 break if fl != self.model.AS.UNK: break c = chr(b) if c < '0' or c in string.punctuation: c = '_' label += c addr += 1 sz += 1 if sz > 0: self.model.AS.set_flags(self.cur_addr(), sz, self.model.AS.STR, self.model.AS.DATA_CONT) self.model.AS.make_unique_label(self.cur_addr(), label) self.update_model() elif key == b"u": addr = self.cur_addr() self.model.undefine_unit(addr) self.update_model() elif key == b"o": addr = self.cur_addr() line = self.get_cur_line() o = line.get_operand_addr() if not o: self.show_status("Cannot convert operand to offset") return if o.type != idaapi.o_imm or not self.model.AS.is_valid_addr(o.get_addr()): self.show_status("Cannot convert operand to offset: #%s: %s" % (o.n, o.type)) return if self.model.AS.get_arg_prop(addr, o.n, "type") == idaapi.o_mem: self.model.AS.set_arg_prop(addr, o.n, "type", idaapi.o_imm) self.model.AS.del_xref(addr, o.get_addr(), idaapi.dr_O) else: self.model.AS.make_arg_offset(addr, o.n, o.get_addr()) self.update_model(True) elif key == b";": addr = self.cur_addr() comment = self.model.AS.get_comment(addr) or "" res = self.dialog_edit_line(line=comment, width=60) if res is not None: self.model.AS.set_comment(addr, res) self.update_model() else: self.update_screen() elif key == b"n": addr = self.cur_addr() label = self.model.AS.get_label(addr) def_label = self.model.AS.get_default_label(addr) s = label or def_label while True: res = self.dialog_edit_line(line=s) if not res: break if res == def_label: res = addr else: if self.model.AS.label_exists(res): s = res self.show_status("Duplicate label") continue self.model.AS.set_label(addr, res) if not label: # If it's new label, we need to add it to model self.update_model() return break self.update_screen() elif key == b"g": d = Dialog(4, 4, title="Go to") d.add(1, 1, WLabel("Label/addr:")) entry = WAutoComplete(20, "", self.model.AS.get_label_list()) entry.popup_h = 12 entry.finish_dialog = ACTION_OK d.add(13, 1, entry) d.add(1, 2, WLabel("Press Down to auto-complete")) res = d.loop() self.update_screen() if res == ACTION_OK: value = entry.get_text() if '0' <= value[0] <= '9': addr = int(value, 0) else: addr = self.model.AS.resolve_label(value) self.goto_addr(addr, from_addr=self.cur_addr()) elif key == editor.KEY_F1: help.help(self) self.update_screen() elif key == b"S": saveload.save_state(project_dir) self.show_status("Saved.") elif key == b"\x11": # ^Q class IssueList(WListBox): def render_line(self, l): return "%08x %s" % l d = Dialog(4, 4, title="Problems list") lw = IssueList(40, 16, self.model.AS.get_issues()) lw.finish_dialog = ACTION_OK d.add(1, 1, lw) res = d.loop() self.update_screen() if res == ACTION_OK: val = lw.get_cur_line() if val: self.goto_addr(val[0], from_addr=self.cur_addr()) elif key == b"i": off, area = self.model.AS.addr2area(self.cur_addr()) props = area[engine.PROPS] percent = 100 * off / (area[engine.END] - area[engine.START] + 1) func = self.model.AS.lookup_func(self.cur_addr()) func = self.model.AS.get_label(func.start) if func else None self.show_status("Area: 0x%x %s (%s): %.1f%%, func: %s" % ( area[engine.START], props.get("name", "noname"), props["access"], percent, func )) elif key == b"I": L = 5 T = 2 W = 66 H = 20 self.dialog_box(L, T, W, H) v = Viewer(L + 1, T + 1, W - 2, H - 2) lines = [] for area in self.model.AS.get_areas(): props = area[engine.PROPS] lines.append("%s (%08x-%08x):" % (props.get("name", "noname"), area[engine.START], area[engine.END])) flags = area[engine.FLAGS] l = "" for i in range(len(flags)): if i % 64 == 0 and l: lines.append(l) l = "" l += engine.flag2char(flags[i]) if l: lines.append(l) v.set_lines(lines) v.loop() self.update_screen() elif key == b"W": out_fname = "out.lst" with open(out_fname, "w") as f: engine.render_partial(TextSaveModel(f, self), 0, 0, 10000000) self.show_status("Disassembly listing written: " + out_fname) elif key == b"\x17": # Ctrl+W outfile = self.write_func(self.cur_addr()) if outfile: self.show_status("Wrote file: %s" % outfile) elif key in (b"/", b"?"): # "/" and Shift+"/" class FoundException(Exception): pass class TextSearchModel: def __init__(self, substr, ctrl): self.search = substr self.ctrl = ctrl self.cnt = 0 def add_line(self, addr, line): line = line.render() if self.search in line: raise FoundException(addr) if self.cnt % 256 == 0: self.ctrl.show_status("Searching: 0x%x" % addr) self.cnt += 1 if key == b"/": d = Dialog(4, 4, title="Text Search") d.add(1, 1, WLabel("Search for:")) entry = WTextEntry(20, self.search_str) entry.finish_dialog = ACTION_OK d.add(13, 1, entry) res = d.loop() self.update_screen() self.search_str = entry.get_text() if res != ACTION_OK or not self.search_str: return addr = self.cur_addr() else: addr = self.next_addr() try: engine.render_from(TextSearchModel(self.search_str, self), addr, 10000000) except FoundException as res: self.goto_addr(res.args[0], from_addr=self.cur_addr()) else: self.show_status("Not found: " + self.search_str) else: self.show_status("Unbound key: " + repr(key))
print( '\tstart_date and end_date may be either YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS[.ffffff] format' ) print('output written to out_lambdas.dat and out_boundaries.dat') def read_input(args): return [ engine.read_datetime(line.strip()) for line in fileinput.input(args) ] if __name__ == '__main__': try: start, end, args = engine.parse_args(sys.argv) except Exception as e: print('Invalid argument.', e) print_usage() sys.exit(1) input_events = read_input(args[1:]) lambdas, boundaries = engine.analyze(input_events, start, end) with open('out_lambdas.dat', 'w') as f: for item in lambdas: f.write("%s\n" % item) with open('out_boundaries.dat', 'w') as f: for item in boundaries: f.write("%s\n" % item)