def start(self):
     #TODO: Handle timeout
     if self._verbose:
         log.info("Trying to connect to target gdb server at %s:%d",
                  self._sockaddress[0], self._sockaddress[1])
     self._gdb_interface = GdbDebugger(gdb_executable=self.gdb_exec)
     self._gdb_interface.set_async_message_handler(
         self.handle_gdb_async_message)
     self._gdb_interface.connect(
         ("tcp", self._sockaddress[0], "%d" % self._sockaddress[1]))
Exemple #2
0
    def run_s2e_process(self):
        try:
            log.info("Starting S2E process: %s", " ".join(["'%s'" % x for x in self._cmdline]))
        
            self._s2e_process = subprocess.Popen(
                        self._cmdline, 
                        cwd = self._configuration.get_output_directory(), 
                        stdout = subprocess.PIPE,
                        stderr = subprocess.PIPE)
            self._s2e_stdout_tee_process = subprocess.Popen(
                    ["tee", os.path.normpath(os.path.join(self._configuration.get_output_directory(),  "s2e_stdout.log"))], 
                    stdin = self._s2e_process.stdout, 
                    cwd = self._configuration.get_output_directory())
            self._s2e_stderr_tee_process = subprocess.Popen(
                    ["tee", os.path.normpath(os.path.join(self._configuration.get_output_directory(),  "s2e_stderr.log"))], 
                    stdin = self._s2e_process.stderr, 
                    cwd = self._configuration.get_output_directory())

            remote_target = False
            if "RemoteMemory" in self._configuration._s2e_configuration["plugins"]:
                remote_target= True

            if remote_target:
                self._remote_memory_interface = S2ERemoteMemoryInterface(self._configuration.get_remote_memory_listen_address())
                self._remote_memory_interface.set_read_handler(self._notify_read_request_handler)
                self._remote_memory_interface.set_write_handler(self._notify_write_request_handler)
                time.sleep(2) #Wait a bit for the S2E process to start
                self._remote_memory_interface.start()

            try:
                gdb_path = self._configuration._s2e_configuration["emulator_gdb_path"]
            except KeyError:
                gdb_path = "arm-none-eabi-gdb"
                log.warn("Using default gdb executable path: %s" % gdb_path)

            self._gdb_interface = GdbDebugger(gdb_executable = gdb_path)
            self._gdb_interface.set_async_message_handler(self.handle_gdb_async_message)
            count = 10
            while count != 0:
                try:
                    log.debug("Trying to connect to emulator.")
                    self._gdb_interface.connect(("tcp", "localhost", "%d" % self._configuration.get_s2e_gdb_port()))
                    break
                except:
                    count -= 1
                    if count > 0:
                        log.warning("Failed to connect to emulator, retrying.")
                    time.sleep(3)
            if count == 0:
                raise Exception("Failed to connect to emulator. Giving up!")
            log.info("Successfully connected to emulator.")
            self._is_s2e_running.set()
            self._s2e_process.wait()
        except KeyboardInterrupt:
            pass
            
        self.exit()
    def start(self):
        #TODO: Handle timeout

        if self._exec_path != "gdb" :
            log.warn("target_gdb_path not defined in avatar configuration, using hardcoded GDB path: %s", self._exec_path)

        if  System(None).is_debug :
            log.info("Trying to connect to target gdb server at %s:%d", self._host, self._port)

        self._gdb_interface = GdbDebugger(gdb_executable = self._exec_path, cwd = ".", additional_args = self._options )
        self._gdb_interface.set_async_message_handler(self.handle_gdb_async_message)

        not_started = False

        while not_started :
            try:
                self._gdb_interface.connect(("tcp", self._host, "%d" % self._port))
                not_started = True
            except TimeoutError :
                if  System(None).is_debug :
                    log.info("Timeout... Connecting to %s:%d again ", self._host, self._port)
                continue
 def start(self):
     #TODO: Handle timeout
     if self._verbose: log.info("Trying to connect to target gdb server at %s:%d", self._sockaddress[0], self._sockaddress[1])
     self._gdb_interface = GdbDebugger(gdb_executable = self.gdb_exec, cwd = ".", additional_args = self.additional_args )
     self._gdb_interface.set_async_message_handler(self.handle_gdb_async_message)
     self._gdb_interface.connect(("tcp", self._sockaddress[0], "%d" % self._sockaddress[1]))
class GdbserverTarget(Target):
    def __init__(self, system, verbose=False):
        self._system = system
        self._verbose = verbose
        
    def init(self):
        conf = self._system.get_configuration()
        assert("avatar_configuration" in conf)
        assert("target_gdb_address" in conf["avatar_configuration"])
        assert(conf["avatar_configuration"]["target_gdb_address"].startswith("tcp:"))
        sockaddr_str = conf["avatar_configuration"]["target_gdb_address"][4:]
        if "target_gdb_path" in conf["avatar_configuration"]:
                self.gdb_exec= conf["avatar_configuration"]["target_gdb_path"]
        else:
            self.gdb_exec = "/home/zaddach/projects/hdd-svn/gdb/gdb/gdb"
            log.warn("target_gdb_path not defined in avatar configuration, using hardcoded GDB path: %s", self.gdb_exec)
        if "target_gdb_additional_arguments" in conf["avatar_configuration"]:
            self.additional_args = conf["avatar_configuration"]["target_gdb_additional_arguments"]
        else:
            self.additional_args = []
        self._sockaddress = (sockaddr_str[:sockaddr_str.rfind(":")],
                             int(sockaddr_str[sockaddr_str.rfind(":") + 1:]))
        
    def start(self):
        #TODO: Handle timeout
        if self._verbose: log.info("Trying to connect to target gdb server at %s:%d", self._sockaddress[0], self._sockaddress[1])
        self._gdb_interface = GdbDebugger(gdb_executable = self.gdb_exec, cwd = ".", additional_args = self.additional_args )
        self._gdb_interface.set_async_message_handler(self.handle_gdb_async_message)
        self._gdb_interface.connect(("tcp", self._sockaddress[0], "%d" % self._sockaddress[1]))
        
    def write_typed_memory(self, address, size, data):
        self._gdb_interface.write_memory(address, size, data)

    def read_typed_memory(self, address, size):
        return self._gdb_interface.read_memory(address, size)

    def set_register(self, reg, val):
        self._gdb_interface.set_register(reg, val)

    def get_register(self, reg):
        return self._gdb_interface.get_register(reg)

    def get_register_from_nr(self, num):
        try:
            return self.get_register(["r0", "r1", "r2", "r3", "r4", "r5",
                "r6", "r7", "r8", "r9", "r10",
                "r11", "r12", "sp", "lr", "pc", "cpsr"][num])
        except IndexError:
            log.warn("get_register_from_nr called with unexpected register index %d", num)
            return 0

    def execute_gdb_command(self, cmd):
        return self._gdb_interface.execute_gdb_command(cmd)
    def get_checksum(self, addr, size):
        return self._gdb_interface.get_checksum(addr, size)
        
    def stop(self):
        pass
    
    def set_breakpoint(self, address, **properties):
        if "thumb" in properties:
            del properties["thumb"]
        bkpt = self._gdb_interface.insert_breakpoint(address, *properties)
        return GdbBreakpoint(self._system, int(bkpt["bkpt"]["number"]))
        
    
    def cont(self):
        self._gdb_interface.cont()
        
    def handle_gdb_async_message(self, msg):
        print("Received async message: '%s'" % str(msg))
        if msg.type == Async.EXEC:
            if msg.klass == "running":
                self._post_event({"tags": [EVENT_RUNNING], "channel": "gdb"})
            elif msg.klass == "stopped":
                if "reason" in msg.results and msg.results["reason"] == "breakpoint-hit":
                    self._post_event({"tags": [EVENT_STOPPED, EVENT_BREAKPOINT],
                                     "properties": {
                                        "address": int(msg.results["frame"]["addr"], 16),
                                        "bkpt_number": int(msg.results["bkptno"])},
                                     "channel": "gdb"})
                elif "reason" in msg.results and msg.results["reason"] == "signal-received":
                    # this is data abort
                    try:
                        addr = int(msg.results["frame"]["addr"], 16)
                    except:
                        addr = 0xDEADDEAD
                    self._post_event({"tags": [EVENT_STOPPED, EVENT_SIGABRT],
                        "properties": {
                            "address": addr,
                            },
                        "channel": "gdb"})
    def _post_event(self, evt):
        evt["source"] = "target"
        self._system.post_event(evt)
    

    @classmethod
    def from_str(cls, sockaddr_str):
        assert(sockaddr_str.startswith("tcp:"))
        sockaddr = (sockaddr_str[:sockaddr_str.rfind(":")],
                    int(sockaddr_str[sockaddr_str.rfind(":") + 1:]))
        return cls(sockaddr)
    def run_s2e_process(self):
        try:
            log.info("Starting S2E process: %s",
                     " ".join(["'%s'" % x for x in self._cmdline]))

            self._s2e_process = subprocess.Popen(
                self._cmdline,
                cwd=self._configuration.get_output_directory(),
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE)
            self._s2e_stdout_tee_process = subprocess.Popen(
                [
                    "tee",
                    os.path.normpath(
                        os.path.join(
                            self._configuration.get_output_directory(),
                            "s2e_stdout.log"))
                ],
                stdin=self._s2e_process.stdout,
                cwd=self._configuration.get_output_directory())
            self._s2e_stderr_tee_process = subprocess.Popen(
                [
                    "tee",
                    os.path.normpath(
                        os.path.join(
                            self._configuration.get_output_directory(),
                            "s2e_stderr.log"))
                ],
                stdin=self._s2e_process.stderr,
                cwd=self._configuration.get_output_directory())

            remote_target = False
            if "RemoteMemory" in self._configuration._s2e_configuration[
                    "plugins"]:
                remote_target = True

            if remote_target:
                self._remote_memory_interface = S2ERemoteMemoryInterface(
                    self._configuration.get_remote_memory_listen_address())
                self._remote_memory_interface.set_read_handler(
                    self._notify_read_request_handler)
                self._remote_memory_interface.set_write_handler(
                    self._notify_write_request_handler)
                self._remote_memory_interface.set_set_cpu_state_handler(
                    self._notify_set_cpu_state_handler)
                self._remote_memory_interface.set_get_cpu_state_handler(
                    self._notify_get_cpu_state_handler)
                self._remote_memory_interface.set_continue_handler(
                    self._notify_continue_handler)
                self._remote_memory_interface.set_get_checksum_handler(
                    self._system.get_target().get_checksum)
                time.sleep(2)  #Wait a bit for the S2E process to start
                self._remote_memory_interface.start()

            try:
                gdb_path = self._configuration._s2e_configuration[
                    "emulator_gdb_path"]
            except KeyError:
                gdb_path = "arm-none-eabi-gdb"
                log.warn("Using default gdb executable path: %s" % gdb_path)

            try:
                gdb_additional_args = self._configuration._s2e_configuration[
                    "emulator_gdb_additional_arguments"]
            except KeyError:
                gdb_additional_args = []

            self._gdb_interface = GdbDebugger(
                gdb_executable=gdb_path,
                cwd=".",
                additional_args=gdb_additional_args)
            self._gdb_interface.set_async_message_handler(
                self.handle_gdb_async_message)
            count = 10
            while count != 0:
                try:
                    log.debug("Trying to connect to emulator.")
                    self._gdb_interface.connect(
                        ("tcp", "127.0.0.1",
                         "%d" % self._configuration.get_s2e_gdb_port()))
                    break
                except:
                    count -= 1
                    if count > 0:
                        log.warning("Failed to connect to emulator, retrying.")
                    time.sleep(3)
            if count == 0:
                raise Exception("Failed to connect to emulator. Giving up!")
            log.info("Successfully connected to emulator.")
            self._is_s2e_running.set()
            self._s2e_process.wait()
        except KeyboardInterrupt:
            pass

        self.exit()
class S2EEmulator(Emulator):
    def __init__(self, system):
        super().__init__(system)
        self._configuration = S2EConfiguration(
            self._system.get_configuration())

    def init(self):
        self._configuration.write_configuration_files(
            self._system.get_configuration()["output_directory"])
        self._cmdline = self._configuration.get_command_line()

    def start(self):
        s2e_processes = find_processes(self._cmdline[0])
        if s2e_processes:
            log.warn(
                "There are still S2E instances running, NOT killing them ...")
            log.warn(
                "Results might be corrupted if output files are not different")
        log.info("Executing S2E process: %s",
                 " ".join(["'%s'" % x for x in self._cmdline]))
        self._s2e_thread = threading.Thread(target=self.run_s2e_process)
        self._is_s2e_running = threading.Event()
        self._s2e_thread.start()
        #TODO: Would be nicer to put this somewhere in a function called is_running
        #so that other stuff can start in parallel and in the end the system waits for everything
        #to be running
        self._is_s2e_running.wait()

    def stop(self):
        if hasattr(self, "_s2e_process"):
            self._s2e_process.kill()

    def exit(self):
        if hasattr(self, "_remote_memory_interface"):
            self._remote_memory_interface.stop()

        print("Exiting")

    def run_s2e_process(self):
        try:
            log.info("Starting S2E process: %s",
                     " ".join(["'%s'" % x for x in self._cmdline]))

            self._s2e_process = subprocess.Popen(
                self._cmdline,
                cwd=self._configuration.get_output_directory(),
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE)
            self._s2e_stdout_tee_process = subprocess.Popen(
                [
                    "tee",
                    os.path.normpath(
                        os.path.join(
                            self._configuration.get_output_directory(),
                            "s2e_stdout.log"))
                ],
                stdin=self._s2e_process.stdout,
                cwd=self._configuration.get_output_directory())
            self._s2e_stderr_tee_process = subprocess.Popen(
                [
                    "tee",
                    os.path.normpath(
                        os.path.join(
                            self._configuration.get_output_directory(),
                            "s2e_stderr.log"))
                ],
                stdin=self._s2e_process.stderr,
                cwd=self._configuration.get_output_directory())

            remote_target = False
            if "RemoteMemory" in self._configuration._s2e_configuration[
                    "plugins"]:
                remote_target = True

            if remote_target:
                self._remote_memory_interface = S2ERemoteMemoryInterface(
                    self._configuration.get_remote_memory_listen_address())
                self._remote_memory_interface.set_read_handler(
                    self._notify_read_request_handler)
                self._remote_memory_interface.set_write_handler(
                    self._notify_write_request_handler)
                self._remote_memory_interface.set_set_cpu_state_handler(
                    self._notify_set_cpu_state_handler)
                self._remote_memory_interface.set_get_cpu_state_handler(
                    self._notify_get_cpu_state_handler)
                self._remote_memory_interface.set_continue_handler(
                    self._notify_continue_handler)
                self._remote_memory_interface.set_get_checksum_handler(
                    self._system.get_target().get_checksum)
                time.sleep(2)  #Wait a bit for the S2E process to start
                self._remote_memory_interface.start()

            try:
                gdb_path = self._configuration._s2e_configuration[
                    "emulator_gdb_path"]
            except KeyError:
                gdb_path = "arm-none-eabi-gdb"
                log.warn("Using default gdb executable path: %s" % gdb_path)

            try:
                gdb_additional_args = self._configuration._s2e_configuration[
                    "emulator_gdb_additional_arguments"]
            except KeyError:
                gdb_additional_args = []

            self._gdb_interface = GdbDebugger(
                gdb_executable=gdb_path,
                cwd=".",
                additional_args=gdb_additional_args)
            self._gdb_interface.set_async_message_handler(
                self.handle_gdb_async_message)
            count = 10
            while count != 0:
                try:
                    log.debug("Trying to connect to emulator.")
                    self._gdb_interface.connect(
                        ("tcp", "127.0.0.1",
                         "%d" % self._configuration.get_s2e_gdb_port()))
                    break
                except:
                    count -= 1
                    if count > 0:
                        log.warning("Failed to connect to emulator, retrying.")
                    time.sleep(3)
            if count == 0:
                raise Exception("Failed to connect to emulator. Giving up!")
            log.info("Successfully connected to emulator.")
            self._is_s2e_running.set()
            self._s2e_process.wait()
        except KeyboardInterrupt:
            pass

        self.exit()

    def write_typed_memory(self, address, size, data):
        self._gdb_interface.write_memory(address, size, data)

    def read_typed_memory(self, address, size):
        return self._gdb_interface.read_memory(address, size)

    def set_register(self, reg, val):
        self._gdb_interface.set_register(reg, val)

    def get_register_from_nr(self, reg_nr):
        return self._gdb_interface.get_register_from_nr(reg_nr)

    def get_register(self, reg):
        return self._gdb_interface.get_register(reg)

    def set_breakpoint(self, address, **properties):
        if "thumb" in properties:
            del properties["thumb"]
        bkpt = self._gdb_interface.insert_breakpoint(address, *properties)
        return S2EBreakpoint(self._system, int(bkpt["bkpt"]["number"]))

    def execute_gdb_command(self, cmd):
        return self._gdb_interface.execute_gdb_command(cmd)

    def cont(self):
        self._gdb_interface.cont()

    def stepi(self):
        self._gdb_interface.stepi()

    def send_signal(self, signalnr):
        self._gdb_interface.send_signal(signalnr)

    def handle_gdb_async_message(self, msg):
        print("Received async message: '%s'" % str(msg))
        if msg.type == Async.EXEC:
            if msg.klass == "running":
                self.post_event({"tags": [EVENT_RUNNING], "channel": "gdb"})
            elif msg.klass == "stopped":
                if "reason" in msg.results and msg.results[
                        "reason"] == "breakpoint-hit":
                    self.post_event({
                        "tags": [EVENT_STOPPED, EVENT_BREAKPOINT],
                        "properties": {
                            "address": int(msg.results["frame"]["addr"], 16),
                            "bkpt_number": int(msg.results["bkptno"])
                        },
                        "channel": "gdb"
                    })
                elif "reason" in msg.results and msg.results[
                        "reason"] == "end-stepping-range":
                    self.post_event({
                        "tags": [EVENT_STOPPED, EVENT_END_STEPPING],
                        "properties": {
                            "address": int(msg.results["frame"]["addr"], 16)
                        },
                        "channel": "gdb"
                    })
                # elif "signal-name" in msg.results and msg.results["signal-name"] == "SIGINT":
                #     self.post_event({"tags": [EVENT_STOPPED, EVENT_END_STEPPING],
                #                      "properties": {
                #                         "address": int(msg.results["frame"]["addr"], 16)
                #                         },
                #                      "channel": "gdb"})

    def post_event(self, evt):
        evt["source"] = "emulator"
        self._system.post_event(evt)
Exemple #8
0
class S2EEmulator(Emulator):
    def __init__(self, s2e_configuration, qemu_configuration, output_directory, configuration_directory):
        self._configuration = S2EConfiguration(s2e_configuration,
            qemu_configuration,
            output_directory,
            configuration_directory)

        self._name = "s2e"

        from avatar.system import System
        self._system = System.getInstance()

        self._output_directory = output_directory

    def __str__(self):

        return self._name

    def init(self):
        self._configuration.write_configuration_files(self._output_directory)
        self._cmdline = self._configuration.get_command_line()

    def start(self):
        s2e_processes = find_processes(self._cmdline[0])
        if s2e_processes:
            log.warn("There are still S2E instances running, NOT killing them ...")
            log.warn("Results might be corrupted if output files are not different")
        self._s2e_thread = threading.Thread(target = self.run_s2e_process)
        self._is_s2e_running = threading.Event()
        self._s2e_thread.start()
        #TODO: Would be nicer to put this somewhere in a function called is_running
        #so that other stuff can start in parallel and in the end the system waits for everything
        #to be running
        self._is_s2e_running.wait()

    def stop(self):
        if hasattr(self, "_s2e_process"):
            self._s2e_process.kill()

    def exit(self):
        if hasattr(self, "_remote_memory_interface"):
            self._remote_memory_interface.stop()

        print("Exiting")

    def run_s2e_process(self):
        try:
            log.info("Starting S2E process \r\n : %s \r\n", " ".join(["'%s'" % x for x in self._cmdline]))

            self._s2e_process = subprocess.Popen(
                        self._cmdline,
                        cwd = self._configuration.get_output_directory(),
                        stdout = subprocess.PIPE,
                        stderr = subprocess.PIPE)
            self._s2e_stdout_tee_process = subprocess.Popen(
                    ["tee", os.path.normpath(os.path.join(self._configuration.get_output_directory(),  "s2e_stdout.log"))],
                    stdin = self._s2e_process.stdout,
                    cwd = self._configuration.get_output_directory())
            self._s2e_stderr_tee_process = subprocess.Popen(
                    ["tee", os.path.normpath(os.path.join(self._configuration.get_output_directory(),  "s2e_stderr.log"))],
                    stdin = self._s2e_process.stderr,
                    cwd = self._configuration.get_output_directory())

            remote_target = False
            if "RemoteMemory" in self._configuration._s2e_configuration["plugins"]:
                remote_target= True

            if remote_target:
                self._remote_memory_interface = S2ERemoteMemoryInterface(self._configuration.get_remote_memory_listen_address())
                self._remote_memory_interface.set_read_handler(self._notify_read_request_handler)
                self._remote_memory_interface.set_write_handler(self._notify_write_request_handler)
                self._remote_memory_interface.set_set_cpu_state_handler(self._notify_set_cpu_state_handler)
                self._remote_memory_interface.set_get_cpu_state_handler(self._notify_get_cpu_state_handler)
                self._remote_memory_interface.set_continue_handler(self._notify_continue_handler)
                self._remote_memory_interface.set_get_checksum_handler(self._notify_get_checksum_handler)
                time.sleep(2) #Wait a bit for the S2E process to start
                self._remote_memory_interface.start()

            try:
                gdb_path = self._configuration._s2e_configuration["gdb_path"]
            except KeyError:
                gdb_path = "arm-none-eabi-gdb"
                log.warn("Using default gdb executable path: %s" % gdb_path)


            try:
                gdb_additional_args = self._configuration._s2e_configuration["gdb_options"]
            except KeyError:
                gdb_additional_args = []

            self._gdb_interface = GdbDebugger(gdb_executable = gdb_path, cwd = ".", additional_args = gdb_additional_args)
            self._gdb_interface.set_async_message_handler(self.handle_gdb_async_message)
            count = 10
            while count != 0:
                try:
                    log.debug("Trying to connect to emulator.")
                    self._gdb_interface.connect(("tcp", "127.0.0.1", "%d" % self._configuration.get_s2e_gdb_port()))
                    break
                except:
                    count -= 1
                    if count > 0:
                        log.warning("Failed to connect to emulator, retrying.")
                    time.sleep(3)
            if count == 0:
                raise Exception("Failed to connect to emulator. Giving up!")
            log.info("Successfully connected to emulator.")
            self._is_s2e_running.set()
            self._s2e_process.wait()
        except (FileNotFoundError, KeyboardInterrupt) as e:
            if type(e).__name__ == "FileNotFoundError" :
                log.error("Wrong path for s2e")
            else :
                pass

        self.exit()

    def write_typed_memory(self, address, size, data):
        self._gdb_interface.write_memory(address, size, data)

    def read_typed_memory(self, address, size):
        return self._gdb_interface.read_memory(address, size)

    def set_register(self, reg, val):
        self._gdb_interface.set_register(reg, val)

    def get_register_from_nr(self, reg_nr):
        return self._gdb_interface.get_register_from_nr(reg_nr)

    def get_register(self, reg):
        return self._gdb_interface.get_register(reg)

    def set_breakpoint(self, address, **properties):
        if "thumb" in properties:
            del properties["thumb"]
        bkpt = self._gdb_interface.insert_breakpoint(address, *properties)
        return S2EBreakpoint(int(bkpt["bkpt"]["number"]))
    def execute_gdb_command(self, cmd):
        return self._gdb_interface.execute_gdb_command(cmd)


    def cont(self):
        self._gdb_interface.cont()

    def stepi(self):
        self._gdb_interface.stepi()

    def send_signal(self, signalnr):
        self._gdb_interface.send_signal(signalnr)

    def handle_gdb_async_message(self, msg):
        print("Received async message: '%s'" % str(msg))
        if msg.type == Async.EXEC:
            if msg.klass == "running":
                self.post_event({"tags": [Event.EVENT_RUNNING], "channel": "gdb"})
            elif msg.klass == "stopped":
                if "reason" in msg.results and msg.results["reason"] == "breakpoint-hit":
                    self.post_event({"tags": [Event.EVENT_STOPPED, Event.EVENT_BREAKPOINT],
                                     "properties": {
                                        "address": int(msg.results["frame"]["addr"], 16),
                                        "bkpt_number": int(msg.results["bkptno"])},
                                     "channel": "gdb"})
                elif "reason" in msg.results and msg.results["reason"] == "end-stepping-range":
                    self.post_event({"tags": [Event.EVENT_STOPPED, Event.EVENT_END_STEPPING],
                                     "properties": {
                                        "address": int(msg.results["frame"]["addr"], 16)
                                        },
                                     "channel": "gdb"})
                # elif "signal-name" in msg.results and msg.results["signal-name"] == "SIGINT":
                #     self.post_event({"tags": [Event.EVENT_STOPPED, Event.EVENT_END_STEPPING],
                #                      "properties": {
                #                         "address": int(msg.results["frame"]["addr"], 16)
                #                         },
                #                      "channel": "gdb"})

    def post_event(self, evt):
        evt["source"] = "emulator"
        System.getInstance().post_event(evt)
class GdbserverTarget(Target):
    def __init__(self, system, verbose=False):
        self._system = system
        self._verbose = verbose

    def init(self):
        conf = self._system.get_configuration()
        assert ("avatar_configuration" in conf)
        assert ("target_gdb_address" in conf["avatar_configuration"])
        assert (conf["avatar_configuration"]["target_gdb_address"].startswith(
            "tcp:"))
        sockaddr_str = conf["avatar_configuration"]["target_gdb_address"][4:]
        if "target_gdb_path" in conf["avatar_configuration"]:
            self.gdb_exec = conf["avatar_configuration"]["target_gdb_path"]
        else:
            self.gdb_exec = "/home/zaddach/projects/hdd-svn/gdb/gdb/gdb"
            log.warn(
                "target_gdb_path not defined in avatar configuration, using hardcoded GDB path: %s",
                self.gdb_exec)
        self._sockaddress = (sockaddr_str[:sockaddr_str.rfind(":")],
                             int(sockaddr_str[sockaddr_str.rfind(":") + 1:]))

    def start(self):
        #TODO: Handle timeout
        if self._verbose:
            log.info("Trying to connect to target gdb server at %s:%d",
                     self._sockaddress[0], self._sockaddress[1])
        self._gdb_interface = GdbDebugger(gdb_executable=self.gdb_exec)
        self._gdb_interface.set_async_message_handler(
            self.handle_gdb_async_message)
        self._gdb_interface.connect(
            ("tcp", self._sockaddress[0], "%d" % self._sockaddress[1]))

    def write_typed_memory(self, address, size, data):
        self._gdb_interface.write_memory(address, size, data)

    def read_typed_memory(self, address, size):
        return self._gdb_interface.read_memory(address, size)

    def set_register(self, reg, val):
        self._gdb_interface.set_register(reg, val)

    def get_register(self, reg):
        return self._gdb_interface.get_register(reg)

    def execute_gdb_command(self, cmd):
        return self._gdb_interface.execute_gdb_command(cmd)

    def get_checksum(self, addr, size):
        return self._gdb_interface.get_checksum(addr, size)

    def stop(self):
        pass

    def set_breakpoint(self, address, **properties):
        if "thumb" in properties:
            del properties["thumb"]
        bkpt = self._gdb_interface.insert_breakpoint(address, *properties)
        return GdbBreakpoint(self._system, int(bkpt["bkpt"]["number"]))

    def cont(self):
        self._gdb_interface.cont()

    def handle_gdb_async_message(self, msg):
        print("Received async message: '%s'" % str(msg))
        if msg.type == Async.EXEC:
            if msg.klass == "running":
                self._post_event({"tags": [EVENT_RUNNING], "channel": "gdb"})
            elif msg.klass == "stopped":
                if "reason" in msg.results and msg.results[
                        "reason"] == "breakpoint-hit":
                    self._post_event({
                        "tags": [EVENT_STOPPED, EVENT_BREAKPOINT],
                        "properties": {
                            "address": int(msg.results["frame"]["addr"], 16),
                            "bkpt_number": int(msg.results["bkptno"])
                        },
                        "channel": "gdb"
                    })

    def _post_event(self, evt):
        evt["source"] = "target"
        self._system.post_event(evt)

    @classmethod
    def from_str(cls, sockaddr_str):
        assert (sockaddr_str.startswith("tcp:"))
        sockaddr = (sockaddr_str[:sockaddr_str.rfind(":")],
                    int(sockaddr_str[sockaddr_str.rfind(":") + 1:]))
        return cls(sockaddr)
class GdbserverTarget(Target):
    def __init__(self, host, port, exec_path="gdb", options=[], log_stdout=False, fname=None):
        self._port = port
        self._host = host
        self._config_file = config_file
        self._exec_path = exec_path
        self._options = options
        self._log_stdout = log_stdout
        self._fname = fname

    def start(self):
        #TODO: Handle timeout

        if self._exec_path != "gdb" :
            log.warn("target_gdb_path not defined in avatar configuration, using hardcoded GDB path: %s", self._exec_path)

        if  System(None).is_debug :
            log.info("Trying to connect to target gdb server at %s:%d", self._host, self._port)

        self._gdb_interface = GdbDebugger(gdb_executable = self._exec_path, cwd = ".", additional_args = self._options )
        self._gdb_interface.set_async_message_handler(self.handle_gdb_async_message)

        not_started = False

        while not_started :
            try:
                self._gdb_interface.connect(("tcp", self._host, "%d" % self._port))
                not_started = True
            except TimeoutError :
                if  System(None).is_debug :
                    log.info("Timeout... Connecting to %s:%d again ", self._host, self._port)
                continue

    def write_typed_memory(self, address, size, data):
        self._gdb_interface.write_memory(address, size, data)

    def read_typed_memory(self, address, size):
        return self._gdb_interface.read_memory(address, size)

    def set_register(self, reg, val):
        self._gdb_interface.set_register(reg, val)

    def get_register(self, reg):
        return self._gdb_interface.get_register(reg)

    def get_register_from_nr(self, num):
        try:
            return self.get_register(["r0", "r1", "r2", "r3", "r4", "r5",
                "r6", "r7", "r8", "r9", "r10",
                "r11", "r12", "sp", "lr", "pc", "cpsr"][num])
        except IndexError:
            log.warn("get_register_from_nr called with unexpected register index %d", num)
            return 0

    def execute_gdb_command(self, cmd):
        return self._gdb_interface.execute_gdb_command(cmd)

    def get_checksum(self, addr, size):
        return self._gdb_interface.get_checksum(addr, size)

    def stop(self):
        pass

    def set_breakpoint(self, address, **properties):
        if "thumb" in properties:
            del properties["thumb"]
        bkpt = self._gdb_interface.insert_breakpoint(address, *properties)
        return GdbBreakpoint(self._system, int(bkpt["bkpt"]["number"]))

    def cont(self):
        self._gdb_interface.cont()

    def handle_gdb_async_message(self, msg):
        print("Received async message: '%s'" % str(msg))
        if msg.type == Async.EXEC:
            if msg.klass == "running":
                self._post_event({"tags": [Event.EVENT_RUNNING], "channel": "gdb"})
            elif msg.klass == "stopped":
                if "reason" in msg.results and msg.results["reason"] == "breakpoint-hit":
                    self._post_event({"tags": [Event.EVENT_STOPPED, Event.EVENT_BREAKPOINT],
                                     "properties": {
                                        "address": int(msg.results["frame"]["addr"], 16),
                                        "bkpt_number": int(msg.results["bkptno"])},
                                     "channel": "gdb"})
                elif "reason" in msg.results and msg.results["reason"] == "signal-received":
                    # this is data abort
                    try:
                        addr = int(msg.results["frame"]["addr"], 16)
                    except:
                        addr = 0xDEADDEAD
                    self._post_event({"tags": [Event.EVENT_STOPPED, Event.EVENT_SIGABRT],
                        "properties": {
                            "address": addr,
                            },
                        "channel": "gdb"})

    def _post_event(self, evt):
        evt["source"] = "target"
        self._system.post_event(evt)

    @classmethod
    def from_str(cls, sockaddr_str):
        assert(sockaddr_str.startswith("tcp:"))
        sockaddr = (sockaddr_str[:sockaddr_str.rfind(":")],
                    int(sockaddr_str[sockaddr_str.rfind(":") + 1:]))
        return cls(sockaddr)
class PandaEmulator(Emulator):
    def __init__(self, system):
        super().__init__(system)
        self._configuration = None  #TODO

    def init(self):
        log.error("Panda init called")
        #TODO: Parse configuration file, generate command line
        # to debug command the emulator
        #self._cmdline = ["gdb", "-ex", "handle SIG38 nostop noprint pass", "-ex", "run", "--args", "/home/vagrant/panda/qemu/arm-softmmu/qemu-system-arm", "-sdl", "-M", "versatilepb", "-kernel", "/home/vagrant/avatar-samples/qemu_uboot/u-boot", "-qmp", "tcp::4000,server,nowait",
        #"-gdb", "tcp::5000,server,nowait", "-S", "-panda", "avatar_memory_hooker:range_uart0=0x101f1000_0x1000,range_uart1=0x101f2000_0x1000,range_uart2=0x101f3000_0x1000,range_uart3=0x10009000_0x1000"]
        ## -S damit der gdb vor der ersten Instruktion abwartet pausiert.
        # Normal (non debug mode)
        self._cmdline = [
            "/home/vagrant/panda/qemu/arm-softmmu/qemu-system-arm", "-sdl",
            "-M", "versatilepb", "-kernel",
            "/home/vagrant/avatar-samples/qemu_uboot/u-boot", "-qmp",
            "tcp::4000,server,nowait", "-gdb", "tcp::5000,server,nowait", "-S",
            "-panda",
            "avatar_memory_hooker:range_uart0=0x101f1000_0x1000,range_uart1=0x101f2000_0x1000,range_uart2=0x101f3000_0x1000,range_uart3=0x10009000_0x1000"
        ]
        # -S damit der gdb vor der ersten Instruktion abwartet pausiert.

    def start(self):
        log.info("Executing Panda process: %s",
                 " ".join(["'%s'" % x for x in self._cmdline]))
        self._panda_thread = threading.Thread(target=self.run_panda_process)
        self._is_panda_running = threading.Event()
        self._panda_thread.start()

        #TODO: Would be nicer to put this somewhere in a function called is_running
        #so that other stuff can start in parallel and in the end the system waits for everything
        #to be running
        self._is_panda_running.wait()

    def stop(self):
        if hasattr(self, "_panda_process"):
            self._panda_process.kill()

    def exit(self):
        if hasattr(self, "_remote_memory_interface"):
            self._remote_memory_interface.stop()

        print("Exiting")

    def run_panda_process(self):
        try:
            log.info("Starting Panda process: %s",
                     " ".join(["'%s'" % x for x in self._cmdline]))

            self._panda_process = subprocess.Popen(
                self._cmdline,
                #cwd = self._configuration.get_output_directory(),
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE)
            self._panda_stdout_tee_process = subprocess.Popen(
                [
                    "tee",
                    os.path.normpath(
                        os.path.join(OUTPUT_DIRECTORY, "panda_stdout.log"))
                ],
                stdin=self._panda_process.stdout,
                cwd=OUTPUT_DIRECTORY)
            self._panda_stderr_tee_process = subprocess.Popen(
                [
                    "tee",
                    os.path.normpath(
                        os.path.join(OUTPUT_DIRECTORY, "panda_stderr.log"))
                ],
                stdin=self._panda_process.stderr,
                cwd=OUTPUT_DIRECTORY)

            self._remote_memory_interface = PandaRemoteMemoryInterface(
                ("127.0.0.1", 5555))
            # Uebergebe callbacks, ein callback ist z.B. self._notify_read_request_handler
            self._remote_memory_interface.set_read_handler(
                self._notify_read_request_handler)
            self._remote_memory_interface.set_write_handler(
                self._notify_write_request_handler)
            self._remote_memory_interface.set_set_cpu_state_handler(
                self._notify_set_cpu_state_handler)
            self._remote_memory_interface.set_get_cpu_state_handler(
                self._notify_get_cpu_state_handler)
            self._remote_memory_interface.set_continue_handler(
                self._notify_continue_handler)
            self._remote_memory_interface.set_get_checksum_handler(
                self._system.get_target().get_checksum)

            # We need some time until the sockets from the RemoteMemory plugin are open
            time.sleep(
                2
            )  #Wait a bit for the Panda process to start, der socket vom Panda Plugin wird
            # tatsaechlich vor dem GDB-emulaor-server socket aufgemacht
            self._remote_memory_interface.start()

            # We need some time until the (potential) sockets from the QMP are open AND
            # until the QEMU-gdb-server socket is open
            time.sleep(2)
            self._monitor_socket = socket.create_connection(
                ("127.0.0.1", 4000))

            try:
                #TODO: Path fuer GDB fuer emulator hier finden
                raise KeyError()
                #gdb_path = self._configuration._panda_configuration["emulator_gdb_path"]
            except KeyError:
                gdb_path = "arm-none-eabi-gdb"
                log.warn("Using default gdb executable path: %s" % gdb_path)

            # try:
            #     gdb_additional_args = self._configuration._panda_configuration["emulator_gdb_additional_arguments"]
            # except KeyError:
            gdb_additional_args = []

            self._gdb_interface = GdbDebugger(
                gdb_executable=gdb_path,
                cwd=".",
                additional_args=gdb_additional_args)
            self._gdb_interface.set_async_message_handler(
                self.handle_gdb_async_message)
            count = 10
            while count != 0:
                try:
                    log.debug("Trying to connect to emulator.")
                    self._gdb_interface.connect(
                        ("tcp", "127.0.0.1", "%d" % 5000))
                    break
                except:
                    count -= 1
                    if count > 0:
                        log.warning("Failed to connect to emulator, retrying.")
                    time.sleep(3)
            if count == 0:
                raise Exception("Failed to connect to emulator. Giving up!")
            log.info("Successfully connected to emulator.")
            self._is_panda_running.set()
            self._panda_process.wait()
        except KeyboardInterrupt:
            pass

        self.exit()

    def enable_remote_memory():
        # TODO
        # talk over QMP to QEMU monitor and enable remote memory, i.e. activate memory callbacks in panda
        # same for disabling
        pass

    # uint_8, uint_16, uint_32, ... i.e. endianess etc.
    def write_typed_memory(self, address, size, data):
        self._gdb_interface.write_memory(address, size, data)

    def read_typed_memory(self, address, size):
        return self._gdb_interface.read_memory(address, size)

    def set_register(self, reg, val):
        self._gdb_interface.set_register(reg, val)

    def get_register_from_nr(self, reg_nr):
        return self._gdb_interface.get_register_from_nr(reg_nr)

    def get_register(self, reg):
        return self._gdb_interface.get_register(reg)

    def set_breakpoint(self, address, **properties):
        if "thumb" in properties:
            del properties["thumb"]
        bkpt = self._gdb_interface.insert_breakpoint(address, *properties)
        return GDBBreakpoint(self._system, int(bkpt["bkpt"]["number"]))

    def execute_gdb_command(self, cmd):
        return self._gdb_interface.execute_gdb_command(cmd)

    def cont(self):
        self._gdb_interface.cont()

    def stepi(self):
        self._gdb_interface.stepi()

    def send_signal(self, signalnr):
        self._gdb_interface.send_signal(signalnr)

    def handle_gdb_async_message(self, msg):
        print("Received async message: '%s'" % str(msg))
        if msg.type == Async.EXEC:
            if msg.klass == "running":
                self.post_event({"tags": [EVENT_RUNNING], "channel": "gdb"})
            elif msg.klass == "stopped":
                if "reason" in msg.results and msg.results[
                        "reason"] == "breakpoint-hit":
                    self.post_event({
                        "tags": [EVENT_STOPPED, EVENT_BREAKPOINT],
                        "properties": {
                            "address": int(msg.results["frame"]["addr"], 16),
                            "bkpt_number": int(msg.results["bkptno"])
                        },
                        "channel": "gdb"
                    })
                elif "reason" in msg.results and msg.results[
                        "reason"] == "end-stepping-range":
                    self.post_event({
                        "tags": [EVENT_STOPPED, EVENT_END_STEPPING],
                        "properties": {
                            "address": int(msg.results["frame"]["addr"], 16)
                        },
                        "channel": "gdb"
                    })
                # elif "signal-name" in msg.results and msg.results["signal-name"] == "SIGINT":
                #     self.post_event({"tags": [EVENT_STOPPED, EVENT_END_STEPPING],
                #                      "properties": {
                #                         "address": int(msg.results["frame"]["addr"], 16)
                #                         },
                #                      "channel": "gdb"})

    def post_event(self, evt):
        evt["source"] = "emulator"
        self._system.post_event(evt)
    def run_panda_process(self):
        try:
            log.info("Starting Panda process: %s",
                     " ".join(["'%s'" % x for x in self._cmdline]))

            self._panda_process = subprocess.Popen(
                self._cmdline,
                #cwd = self._configuration.get_output_directory(),
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE)
            self._panda_stdout_tee_process = subprocess.Popen(
                [
                    "tee",
                    os.path.normpath(
                        os.path.join(OUTPUT_DIRECTORY, "panda_stdout.log"))
                ],
                stdin=self._panda_process.stdout,
                cwd=OUTPUT_DIRECTORY)
            self._panda_stderr_tee_process = subprocess.Popen(
                [
                    "tee",
                    os.path.normpath(
                        os.path.join(OUTPUT_DIRECTORY, "panda_stderr.log"))
                ],
                stdin=self._panda_process.stderr,
                cwd=OUTPUT_DIRECTORY)

            self._remote_memory_interface = PandaRemoteMemoryInterface(
                ("127.0.0.1", 5555))
            # Uebergebe callbacks, ein callback ist z.B. self._notify_read_request_handler
            self._remote_memory_interface.set_read_handler(
                self._notify_read_request_handler)
            self._remote_memory_interface.set_write_handler(
                self._notify_write_request_handler)
            self._remote_memory_interface.set_set_cpu_state_handler(
                self._notify_set_cpu_state_handler)
            self._remote_memory_interface.set_get_cpu_state_handler(
                self._notify_get_cpu_state_handler)
            self._remote_memory_interface.set_continue_handler(
                self._notify_continue_handler)
            self._remote_memory_interface.set_get_checksum_handler(
                self._system.get_target().get_checksum)

            # We need some time until the sockets from the RemoteMemory plugin are open
            time.sleep(
                2
            )  #Wait a bit for the Panda process to start, der socket vom Panda Plugin wird
            # tatsaechlich vor dem GDB-emulaor-server socket aufgemacht
            self._remote_memory_interface.start()

            # We need some time until the (potential) sockets from the QMP are open AND
            # until the QEMU-gdb-server socket is open
            time.sleep(2)
            self._monitor_socket = socket.create_connection(
                ("127.0.0.1", 4000))

            try:
                #TODO: Path fuer GDB fuer emulator hier finden
                raise KeyError()
                #gdb_path = self._configuration._panda_configuration["emulator_gdb_path"]
            except KeyError:
                gdb_path = "arm-none-eabi-gdb"
                log.warn("Using default gdb executable path: %s" % gdb_path)

            # try:
            #     gdb_additional_args = self._configuration._panda_configuration["emulator_gdb_additional_arguments"]
            # except KeyError:
            gdb_additional_args = []

            self._gdb_interface = GdbDebugger(
                gdb_executable=gdb_path,
                cwd=".",
                additional_args=gdb_additional_args)
            self._gdb_interface.set_async_message_handler(
                self.handle_gdb_async_message)
            count = 10
            while count != 0:
                try:
                    log.debug("Trying to connect to emulator.")
                    self._gdb_interface.connect(
                        ("tcp", "127.0.0.1", "%d" % 5000))
                    break
                except:
                    count -= 1
                    if count > 0:
                        log.warning("Failed to connect to emulator, retrying.")
                    time.sleep(3)
            if count == 0:
                raise Exception("Failed to connect to emulator. Giving up!")
            log.info("Successfully connected to emulator.")
            self._is_panda_running.set()
            self._panda_process.wait()
        except KeyboardInterrupt:
            pass

        self.exit()