예제 #1
0
def co_update_device_tree(qemu_exec, src_path, arch_name, root):
    dic = create_dwarf_cache(qemu_exec)

    gvl_adptr = GitLineVersionAdapter(src_path)

    qomtr = QOMTreeReverser(dic,
                            interrupt=True,
                            verbose=True,
                            line_adapter=gvl_adptr)

    port = find_free_port(4321)
    qemu_debug_addr = "localhost:%u" % port
    Popen(["gdbserver", qemu_debug_addr, qemu_exec])

    if not wait_for_tcp_port(port):
        raise RuntimeError("gdbserver does not listen %u" % port)

    yield True

    qemu_debugger = AMD64(str(port), noack=True)
    rt = Runtime(qemu_debugger, dic)

    qomtr.init_runtime(rt)

    yield rt.co_run_target()

    device_subtree = qomtr.tree.name2type.get("device", None)

    if device_subtree is None:
        raise RuntimeError(
            'No "device" QOM subtree. Did you forget to pass ' +
            '"--extra-cflags=-no-pie" and/or "--disable-pie" to `configure`?')

    yield co_fill_children(device_subtree, root, arch_name)
예제 #2
0
 def reset(self, srcfile, elffile):
     self.srcfile = srcfile
     self.elffile = elffile
     self.elf = InMemoryELFFile(elffile)
     di = self.elf.get_dwarf_info()
     dic = DWARFInfoCache(di,
                          symtab=self.elf.get_section_by_name(".symtab"))
     if dic.aranges is None:
         dic.account_all_subprograms()
     self.rt = Runtime(self.rsp, dic)
     self.addr2line = {}
     self.ch_line2var = defaultdict(list)
     self.chc_line2var = defaultdict(list)
예제 #3
0
class DebugSession(object):
    """ This class manages debugging session """
    def __init__(self, target, srcfile, port, elffile, queue, verbose):
        super(DebugSession, self).__init__()
        self.rsp = target(port, verbose=verbose)
        self.port = port
        self.queue = queue
        self.reset(srcfile, elffile)
        self.session_type = None

    def reset(self, srcfile, elffile):
        self.srcfile = srcfile
        self.elffile = elffile
        self.elf = InMemoryELFFile(elffile)
        di = self.elf.get_dwarf_info()
        dic = DWARFInfoCache(di,
                             symtab=self.elf.get_section_by_name(".symtab"))
        if dic.aranges is None:
            dic.account_all_subprograms()
        self.rt = Runtime(self.rsp, dic)
        self.addr2line = {}
        self.ch_line2var = defaultdict(list)
        self.chc_line2var = defaultdict(list)

    def set_br_by_line(self, lineno, cb):
        line_map = self.rt.dic.find_line_map(bstr(basename(self.srcfile)))
        line_descs = line_map[lineno]
        for desc in line_descs:
            # TODO: set a breakpoint at one address by line number?
            # if desc.state.is_stmt:
            addr = self.rt.target.reg_fmt % desc.state.address
            self.addr2line[addr] = lineno
            self.rt.add_br(addr, cb)
            # break

    def _execute_debug_comment(self):
        lineno = 1

        with open(self.srcfile, 'r') as f:
            re_comment = compile("^.*//\$(.+)$")
            for line in f:
                mi = re_comment.match(line)
                if mi:
                    glob = DebugCommandExecutor(locals(), lineno)
                    exec(mi.group(1), glob)
                lineno += 1

    @property
    def _var_size(self):
        re_size = compile("^.+_(?:u?(\d+))_.+$")
        size_str = re_size.match(basename(self.srcfile)).group(1)
        return int(size_str) // 8

    def _dump_var(self, addr, lineno, var_names):
        dump = (self.session_type, self.srcfile,
                dict(elf=self.elffile,
                     addr=addr,
                     lineno=lineno,
                     vars=dict(
                         map(lambda x: (x, self.rt[x].fetch(self._var_size)),
                             var_names if var_names else self.rt)),
                     regs=self.rt.target.regs))
        if self.rt.target.verbose:
            print(dump[2].values())
        self.queue.put(dump)

    def _dump(self, addr, lineno):
        dump = (self.session_type, self.srcfile,
                dict(elf=self.elffile,
                     addr=addr,
                     lineno=lineno,
                     regs=self.rt.target.regs))
        if self.rt.target.verbose:
            print(dump[2].values())
        self.queue.put(dump)

    # debugging callbacks
    def check_cb(self):
        addr = self.rt.target.regs[self.rt.target.pc_reg]
        lineno = self.addr2line[addr]

        self._dump(addr, lineno)
        self.rt.remove_br(addr, self.check_cb)

    def cycle_check_cb(self):
        addr = self.rt.target.regs[self.rt.target.pc_reg]
        lineno = self.addr2line[addr]

        self._dump(addr, lineno)

    def check_vars_cb(self):
        addr = self.rt.target.regs[self.rt.target.pc_reg]
        lineno = self.addr2line[addr]

        var_names = self.ch_line2var.get(lineno)

        self._dump_var(addr, lineno, var_names)
        self.rt.remove_br(addr, self.check_vars_cb)

    def cycle_check_vars_cb(self):
        addr = self.rt.target.regs[self.rt.target.pc_reg]
        lineno = self.addr2line[addr]

        var_names = self.chc_line2var.get(lineno)

        self._dump_var(addr, lineno, var_names)

    def finish_cb(self):
        addr = self.rt.target.regs[self.rt.target.pc_reg]
        self.rt.remove_br(addr, self.finish_cb)

        for br in list(self.rt.target.br):
            self.rt.target.del_br(br)
        self.rt.target.exit = True

    # end debugging callbacks

    def kill(self):
        self.rt.target.send(b'k')

    def detach(self):
        self.rt.target.send(b'D')

    def port_close(self):
        self.rt.target.port.close()
예제 #4
0
파일: qw.py 프로젝트: dimas3452/qdt
def main():
    ap = QArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter,
                         description="QEMU runtime introspection tool")
    ap.add_argument("-q", dest="qsrc", help="QEMU src directory.")
    ap.add_argument(
        "-c",
        "--connect",
        nargs="?",
        metavar="HOST",
        const="127.0.0.1",  # default if `-c` is given without a value
        # Suppress reasons:
        # 1. do not print incorrect default in help by
        #    `ArgumentDefaultsHelpFormatter` (correct is `const`)
        # 2. do not add the attribute to parsed args if the arg is missed
        default=SUPPRESS,
        help="connect to existing gdbstub (default: %(const)s)")
    ap.add_argument("-p",
                    "--port",
                    type=int,
                    metavar="PORT",
                    default=4321,
                    help="start search for unused port from this number")
    ap.add_argument(
        "qarg",
        nargs="+",
        help="QEMU executable and arguments to it. Prefix them with `--`.")
    args = ap.parse_args()

    # executable
    qemu_cmd_args = args.qarg

    # src directory
    qemu_src_dir = args.qsrc

    # debug info
    qemu_debug = qemu_cmd_args[0]

    elf = InMemoryELFFile(qemu_debug)
    if not elf.has_dwarf_info():
        stderr("%s does not have DWARF info. Provide a debug QEMU build\n" %
               (qemu_debug))
        return -1

    di = elf.get_dwarf_info()

    if not di.debug_pubnames_sec:
        print("%s does not contain .debug_pubtypes section. Provide"
              " -gpubnames flag to the compiler" % qemu_debug)

    dic = DWARFInfoCache(di, symtab=elf.get_section_by_name(".symtab"))

    if qemu_src_dir:
        gvl_adptr = GitLineVersionAdapter(qemu_src_dir)
    else:
        gvl_adptr = None

    qomtr = QOMTreeReverser(dic,
                            interrupt=False,
                            verbose=True,
                            line_adapter=gvl_adptr)

    if "-i386" in qemu_debug or "-x86_64" in qemu_debug:
        MWClass = PCMachineWatcher
    else:
        MWClass = MachineWatcher

    mw = MWClass(dic, qomtr.tree, interrupt=True, line_adapter=gvl_adptr)

    proj = GUIProject()
    pht = GUIProjectHistoryTracker(proj, proj.history)

    MachineReverser(mw, pht)

    try:
        qemu_debug_addr_fmt = args.connect + ":%u"
    except AttributeError:  # no -c/--connect option
        # auto select free port for gdb-server
        port = find_free_port(args.port)

        qemu_debug_addr = "localhost:%u" % port

        qemu_proc = Popen(["gdbserver", qemu_debug_addr] + qemu_cmd_args)
    else:
        port = args.port
        qemu_debug_addr = qemu_debug_addr_fmt % port
        qemu_proc = None

    if not wait_for_tcp_port(port):
        raise RuntimeError("gdbserver does not listen %u" % port)

    qemu_debugger = AMD64(str(port), noack=True)

    rt = Runtime(qemu_debugger, dic)

    qomtr.init_runtime(rt)
    mw.init_runtime(rt)

    # Because pyrsp (with machine reconstruction suite) works in a separate
    # thread, tracker's "changed" notifications are racing with GUI. So, GUI
    # must not watch those notifications. To maintain GUI consistency
    # other project and tracker are created with same history. The GUI is
    # watching this second tracker. A special coroutine working in GUI thread
    # will poll first (master) tracker position and adjust second (slave)
    # tracker updating the GUI without races.
    proj2 = GUIProject()
    # different context (project) but same history
    slave_pht = GUIProjectHistoryTracker(proj2, proj.history)

    def co_syncronizer():
        while True:
            if slave_pht.pos != pht.pos:
                yield True
                slave_pht.do()
            else:
                yield False

    tk = QEmuWatcherGUI(slave_pht, rt)

    tk.task_manager.enqueue(co_syncronizer())

    tk.geometry("1024x1024")
    tk.mainloop()

    qomtr.to_file("qom-by-q.i.dot")

    if qemu_proc is not None:
        qemu_proc.wait()

    if gvl_adptr is not None:
        gvl_adptr.cm.store_cache()