├── .gitignore ├── COPYRIGHT ├── HOWTO.md ├── LICENSE ├── MANIFEST.in ├── README.rst ├── avatar ├── __init__.py ├── bintools │ ├── LICENSE │ ├── __init__.py │ └── gdb │ │ ├── __init__.py │ │ ├── gdb_debugger.py │ │ ├── mi.py │ │ ├── mi_parser.py │ │ ├── parse_stream.py │ │ ├── readme.txt │ │ └── rsp.py ├── call_proxy.py ├── debuggable.py ├── emulators │ ├── __init__.py │ ├── emulator.py │ ├── null_emulator.py │ └── s2e │ │ ├── __init__.py │ │ ├── configuration.py │ │ ├── debug_s2e_emulator.py │ │ └── s2e_emulator.py ├── interfaces │ ├── __init__.py │ ├── avatar_stub │ │ ├── __init__.py │ │ ├── avatar_exceptions.py │ │ ├── avatar_messages.py │ │ ├── avatar_protocol.py │ │ └── avatar_protocol_lowlevel.py │ ├── gdb │ │ ├── __init__.py │ │ ├── avatar_gdb_bridge.py │ │ ├── errors.py │ │ ├── gdb_server.py │ │ ├── protocol.py │ │ └── protocol_lowlevel.py │ └── s2e_remote_memory.py ├── plugins │ ├── __init__.py │ ├── avatar_plugin.py │ └── memory_range_identifier.py ├── system.py ├── targets │ ├── __init__.py │ ├── avatarstub_target.py │ ├── gdbserver_target.py │ ├── jig.py │ ├── null_target.py │ ├── openocd_jig.py │ ├── openocd_target.py │ └── target.py └── util │ ├── __init__.py │ ├── checksum.py │ ├── indexable_queue.py │ ├── ostools.py │ ├── processes.py │ ├── reference.py │ └── socket_file.py ├── binary_translator ├── CMakeLists.txt ├── cmake │ └── FindLLVM.cmake ├── include │ └── lldc │ │ ├── ArmReverseTranslators.h │ │ ├── ArrayMemoryObject.h │ │ ├── BasicBlockCache.h │ │ ├── ExtendedMCInst.h │ │ ├── FunctionCache.h │ │ ├── GeneratedBasicBlocks.h │ │ ├── InstructionDecoder.h │ │ ├── InstructionTranslationUnitCache.h │ │ ├── InstrumentMemoryAccessPass.h │ │ ├── LLVMArmInstructions.h │ │ ├── LLVMArmRegisters.h │ │ ├── NextInstructions.h │ │ ├── PathState.h │ │ ├── PathsManager.h │ │ ├── ProxyMemoryObject.h │ │ ├── RecordingMemoryManager.h │ │ ├── ReverseTranslateBasicBlock.h │ │ ├── ReverseTranslationConfiguration.h │ │ ├── ReverseTranslatorExceptions.h │ │ ├── SystemInformation.h │ │ ├── c_interface.h │ │ ├── test_code.h │ │ └── util.h ├── src │ ├── ArmReverseTranslators.cpp │ ├── ArrayMemoryObject.cpp │ ├── BasicBlockCache.cpp │ ├── FunctionCache.cpp │ ├── InstructionDecoder.cpp │ ├── InstructionTranslationUnitCache.cpp │ ├── InstrumentMemoryAccessPass.cpp │ ├── PathState.cpp │ ├── PathsManager.cpp │ ├── ProxyMemoryObject.cpp │ ├── RecordingMemoryManager.cpp │ ├── ReverseTranslationConfiguration.cpp │ ├── c_interface.cpp │ ├── python_interface.c │ ├── test_code.cpp │ ├── translate_arm.cpp │ └── util.cpp ├── test_translation.c └── test_translation.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | *.swp 3 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright 2013-2014 Institut Eurecom 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | 15 | Some of the files under the bintools directory come from the pydevtools 16 | project and are available under a BSD-3 license. 17 | -------------------------------------------------------------------------------- /HOWTO.md: -------------------------------------------------------------------------------- 1 | === How to reverse engineer a device with Avatar === 2 | 3 | == Using JTAG == 4 | 5 | == Using a software debugger (GDB stub) == 6 | * Dump everything of the code that you can get. 7 | * Reverse engineer code to understand how to use the serial port and to find a suitable first 8 | memory location for the GDB stub. 9 | * Find a way to inject and execute code on the embedded system. 10 | * Adapt the GDB stub for your target, i.e., set up a start file that puts the stack in the right 11 | location, and add a driver for the serial port (or use an existing driver if you are lucky enough 12 | to have a known serial port) 13 | * Write a flasher script that copies the GDB stub to the target and executes it 14 | * Run the GDB stub and poke around in memory to see if there are any memory regions you don't know of yet ... 15 | in particular look for a ROM code section that sets up a very basic environment and loads code from 16 | flash/serial port/etc. Probing the memory can be annoying if the device reboots on an invalid memory access. 17 | * Extract the ROM loader code 18 | * Create an AVATAR script that forwards all memory accesses except for the ROM code and the serial port for 19 | your device and start executing. -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include avatar * 2 | recursive-include binary_translator * 3 | include README.rst 4 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Avatar: dynamic firmware analysis 2 | ================================= 3 | 4 | This repository contains the Python library which constitutes the core 5 | of the `Avatar framework `_. 6 | 7 | Examples 8 | -------- 9 | 10 | Some devices have been analysed in our NDSS'14 paper, code examples are 11 | available in the `avatar-samples 12 | repository `_. 13 | -------------------------------------------------------------------------------- /avatar/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | #from configuration.manager import ConfigurationManager 3 | 4 | #config = ConfigurationManager() -------------------------------------------------------------------------------- /avatar/bintools/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Cambridge Silicon Radio Ltd. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright notice, 9 | this list of conditions and the following disclaimer in the documentation and/or 10 | other materials provided with the distribution. 11 | 3. Neither the name of the Cambridge Silicon Radio Ltd. nor the names of its 12 | contributors may be used to endorse or promote products derived from this 13 | software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 22 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /avatar/bintools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avatarone/avatar-python/c6d74f85f63333e3031e1f5e208d3f90e316a9e4/avatar/bintools/__init__.py -------------------------------------------------------------------------------- /avatar/bintools/gdb/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avatarone/avatar-python/c6d74f85f63333e3031e1f5e208d3f90e316a9e4/avatar/bintools/gdb/__init__.py -------------------------------------------------------------------------------- /avatar/bintools/gdb/gdb_debugger.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Jul 1, 2013 3 | 4 | @author: Jonas Zaddach 5 | ''' 6 | from avatar.bintools.gdb.mi import GDB, Debugger 7 | import logging 8 | from avatar.bintools.gdb.mi_parser import Stream 9 | 10 | log = logging.getLogger(__name__) 11 | 12 | class GdbDebugger(Debugger): 13 | def __init__(self, gdb_executable = "gdb", cwd = ".", additional_args = []): 14 | self._async_message_handler = None 15 | self._stream_handler = None 16 | self._register_names = None 17 | self._gdb = GDB(self, executable = gdb_executable, cwd = cwd, additional_args = additional_args) 18 | 19 | def insert_breakpoint(self, 20 | line, 21 | hardware = False, 22 | temporary = False, 23 | regex = False, 24 | condition = None, 25 | ignore_count = 0, 26 | thread = 0): 27 | cmd = ["-break-insert"] 28 | if temporary: 29 | cmd.append("-t") 30 | if hardware: 31 | cmd.append("-h") 32 | if regex: 33 | assert((not temporary) and (not condition) and (not ignore_count)) 34 | cmd.append("-r") 35 | if condition: 36 | cmd.append("-c") 37 | cmd.append(str(condition)) 38 | if ignore_count: 39 | cmd.append("-i") 40 | cmd.append("%d" % ignore_count) 41 | if thread: 42 | cmd.append("-p") 43 | cmd.append("%d" % thread) 44 | 45 | if isinstance(line, int): 46 | cmd.append("*0x%x" % line) 47 | else: 48 | cmd.append(str(line)) 49 | 50 | return self._gdb.sync_cmd(cmd, "done") 51 | 52 | def execute_gdb_command(self, cmd): 53 | if not isinstance(cmd, list): 54 | cmd = [cmd] 55 | return self._gdb.sync_cmd(cmd, "done") 56 | 57 | def write_memory(self, address, size, val): 58 | str_size = {1: "char", 2: "short", 4: "long"}[size] 59 | self._gdb.sync_cmd(["-gdb-set", "*((%s *) 0x%x)=0x%x" % (str_size, address, val)], "done") 60 | 61 | def read_memory(self, address, size): 62 | str_size = {1: "char", 2: "short", 4: "long"}[size] 63 | result = self._gdb.sync_cmd(["-data-read-memory", "0x%x" % address, "x", "%d" % size, "1", "1"], "done") 64 | return int(result["memory"][0]["data"][0], 16) 65 | 66 | def get_checksum(self, address, size): 67 | result = self._gdb.sync_cmd(["-gdb-show", "remote", "checksum", "%x" % address, "%x" % size], "done") 68 | print("And the result is: " + repr(result)) 69 | return int(result["value"], 10) 70 | 71 | def map_register_name(self, reg): 72 | if not self._register_names: 73 | #Fetch register names ... 74 | result = self._gdb.sync_cmd(["-data-list-register-names"], "done") 75 | self._register_names = dict(filter(lambda x: x[0] != "", zip(result["register-names"], range(0, 10000)))) 76 | 77 | return self._register_names[reg] 78 | 79 | def get_register(self, reg): 80 | return self.get_register_from_nr(self.map_register_name(reg)) 81 | 82 | def get_register_from_nr(self, reg_num): 83 | try : 84 | result = self._gdb.sync_cmd(["-data-list-register-values", "x", "%d" % reg_num], "done") 85 | ret=int(result["register-values"][0]["value"], 16) 86 | except: 87 | log.error("register nr %s was requested but (probably) does not exist: returning 0",reg_num) 88 | ret=0 89 | return ret 90 | 91 | def set_register(self, reg, value): 92 | #reg_num = self.map_register_name(reg) 93 | self._gdb.sync_cmd(["-gdb-set", "$%s=0x%x" % (reg, value)], "done") 94 | 95 | def delete_breakpoint(self, bkpt): 96 | self._gdb.sync_cmd(["-break-delete", "%d" % bkpt], "done") 97 | 98 | def stepi(self): 99 | self._gdb.sync_cmd(["-exec-step-instruction"], "running") 100 | 101 | def cont(self): 102 | self._gdb.sync_cmd(["-exec-continue"], "running") 103 | 104 | def send_signal(self, signalnr): 105 | self._gdb.sync_cmd(["-exec-interrupt"],"done") 106 | 107 | def connect(self, proto_addr_port): 108 | log.debug("Connecting to remote gdb: %s", ":".join(proto_addr_port)) 109 | self._gdb.sync_cmd(["-target-select", "remote", ":".join(proto_addr_port)], "connected") 110 | 111 | def handle_async(self, msg): 112 | if self._async_message_handler: 113 | self._async_message_handler(msg) 114 | 115 | def handle_stream_msg(self, msg): 116 | if self._stream_handler: 117 | self._stream_handler(msg) 118 | else: 119 | if msg.type == Stream.CONSOLE: 120 | log.info(msg.string) 121 | elif msg.type == Stream.TARGET: 122 | log.info('> %s' % msg.string) 123 | elif msg.type == Stream.ERROR_LOG: 124 | log.error(msg.string) 125 | 126 | def set_async_message_handler(self, handler): 127 | self._async_message_handler = handler 128 | 129 | def set_output_stream_handler(self, handler): 130 | self._stream_handler = handler 131 | -------------------------------------------------------------------------------- /avatar/bintools/gdb/mi.py: -------------------------------------------------------------------------------- 1 | from subprocess import Popen, PIPE, STDOUT 2 | from threading import Thread 3 | from queue import Queue 4 | from os import read, getcwd 5 | from os.path import join 6 | import select 7 | import errno 8 | from logging import getLogger, debug, info, error, basicConfig, exception, DEBUG #, INFO 9 | 10 | from avatar.bintools.gdb.mi_parser import parse, Stream, Async, Result 11 | 12 | log = getLogger("GDB-MI") 13 | 14 | class Debugger: 15 | def handle_stream_msg(self, msg): 16 | if msg.type == Stream.CONSOLE: 17 | info(msg.string) 18 | elif msg.type == Stream.TARGET: 19 | info('> %s' % msg.string) 20 | elif msg.type == Stream.ERROR_LOG: 21 | error(msg.string) 22 | 23 | def handle_async(self, msg): 24 | # These messages should change the state of the debugger to reflect 25 | # changes in the remote target 26 | pass 27 | 28 | class MIProtocolException(Exception): 29 | def __init__(self, message): 30 | super(MIProtocolException, self).__init__(message) 31 | 32 | class GDB(Thread): 33 | PROMPT = '(gdb)' 34 | # '-tty', '/dev/pts/4', '--command=.gdbinit' 35 | CMD = ['-q', '-nowindows', '-nx', '-i', 'mi'] 36 | MSG_EOF, MSG_TERM = 0, 1 37 | TERMINATOR = '(gdb) ' 38 | 39 | def __init__(self, dbg = None, executable = "gdb", cwd = ".", additional_args = []): 40 | Thread.__init__(self) 41 | cmd = [executable] + GDB.CMD + additional_args 42 | log.info("Creating GDB instance: %s" % (" ".join(["\"%s\"" % x for x in cmd]),)) 43 | self.gdb = Popen(cmd, 44 | stdin=PIPE, 45 | stdout=PIPE, 46 | stderr=STDOUT, 47 | universal_newlines=True, 48 | cwd = join(getcwd(), cwd)) 49 | self.results_queue = Queue() 50 | self.token = 1 51 | self.dbg = dbg 52 | self.start() 53 | 54 | def send_cmd(self, cmd): 55 | cmd_str = '%d%s' % (self.token, " ".join(cmd)) 56 | debug('[TX] %s' % cmd_str) 57 | t = self.token 58 | self.gdb.stdin.write(cmd_str + '\n') 59 | self.gdb.stdin.flush() 60 | self.token += 1 61 | return t 62 | 63 | def add_msg(self, msg): 64 | debug('[RX] %s' % msg) 65 | msg = parse(msg) 66 | if isinstance(msg, Stream): 67 | self.dbg.handle_stream_msg(msg) 68 | elif isinstance(msg, Async): 69 | self.dbg.handle_async(msg) 70 | elif isinstance(msg, Result): 71 | self.results_queue.put(msg) 72 | 73 | def get_result(self, t=None): 74 | msg = self.results_queue.get() 75 | if t is not None and msg.token != t: 76 | raise MIProtocolException("Expected token %d, received token %d." % (t, msg.token)) 77 | return msg 78 | 79 | def sync_cmd(self, cmd, klass='done'): 80 | t = self.send_cmd(cmd) 81 | r = self.get_result(t) 82 | if r.klass != klass: 83 | raise MIProtocolException('Expected "%s" notification, received %s' % (klass, r.klass)) 84 | return r.results 85 | 86 | def run(self): 87 | buffer = '' 88 | while True: 89 | try: 90 | select.select([self.gdb.stdout], [], []) 91 | except select.error as e: 92 | if e.args[0] == errno.EINTR: 93 | continue 94 | raise 95 | 96 | data = read(self.gdb.stdout.fileno(), 1024).decode(encoding = 'ascii') 97 | if data == "": 98 | if buffer: 99 | raise MIProtocolException("Incomplete message: %s" % buffer) 100 | # self.results_queue.put(GDB.MSG_EOF) 101 | debug('[RX] EOF') 102 | break 103 | 104 | data = buffer + data 105 | buffer = '' 106 | 107 | msg = [] 108 | for c in data: 109 | if c == '\n': 110 | msg_line = ''.join(msg) 111 | if msg_line == GDB.TERMINATOR: 112 | # self.results_queue.put(GDB.MSG_TERM) 113 | debug('[RX] (gdb)') 114 | else: 115 | if msg_line == '^done': 116 | msg = [] 117 | break 118 | try: 119 | self.add_msg(msg_line) 120 | except MIProtocolException: 121 | exception("Exception while parsing GDB reply: %s" % (msg_line)) 122 | msg = [] 123 | else: 124 | msg.append(c) 125 | 126 | if msg: 127 | msg = ''.join(msg) 128 | if msg == GDB.TERMINATOR: 129 | # self.results_queue.put(GDB.MSG_TERM) 130 | debug('[RX] (gdb)') 131 | else: 132 | buffer = msg 133 | 134 | def set(self, key, var): 135 | self.sync_cmd('-gdb-set %s %s' % (key, str(var))) 136 | 137 | def set_vars(self, variables): 138 | for key, value in variables.items(): 139 | self.set(key, value) 140 | 141 | 142 | def init(self): 143 | self.set_vars({ 144 | 'confirm': 'off', 145 | 'width': 0, 146 | 'height': 0, 147 | 'auto-solib-add': 'on', 148 | 'stop-on-solib-events': 1, 149 | }) 150 | self.sync_cmd('-interpreter-exec console echo') 151 | 152 | 153 | 154 | if __name__ == '__main__': 155 | basicConfig(level=DEBUG, format='%(levelname)-8s %(message)s') 156 | dbg = Debugger() 157 | gdb = GDB('/home/em01/workspace/TestGDB', 'Debug/TestGDB', dbg) 158 | gdb.start() 159 | 160 | gdb.init() 161 | 162 | print('done') 163 | 164 | -------------------------------------------------------------------------------- /avatar/bintools/gdb/parse_stream.py: -------------------------------------------------------------------------------- 1 | class ParseError(Exception): 2 | pass 3 | 4 | 5 | class ParseStreamError(ParseError): 6 | def __init__(self, msg, s): 7 | ParseError.__init__(self, '%s: %s@%d' % (msg, s.getvalue(), s.pos)) 8 | 9 | 10 | class ParseStream(): 11 | def __init__(self, string): 12 | self._string = string 13 | self._pos = 0 14 | 15 | def char(self): 16 | return self.read(1) 17 | 18 | def read(self, num): 19 | data = self._string[self._pos:self._pos + num] 20 | self._pos += num 21 | return data 22 | 23 | def seek(self, pos): 24 | assert(pos >= 0 and pos < len(self._string)) 25 | self._pos = pos 26 | 27 | def back(self, n=1): 28 | self.seek(self._pos - n) 29 | 30 | def skip(self, n=1): 31 | self.seek(self._pos + n) 32 | 33 | def peek(self): 34 | c = self.read(1) 35 | self.back() 36 | return c 37 | 38 | def next_char(self, rc): 39 | if self._pos + 1 >= len(self._string): 40 | return False 41 | c = self.read(1) 42 | if c != rc: 43 | self.back() 44 | return False 45 | return True 46 | 47 | def expect_char(self, expected): 48 | c = self.read(1) 49 | if c != expected: 50 | raise ParseStreamError('Expected "%c", got "%c"' % (expected, c), self) 51 | 52 | def check_limit(self): 53 | if self._pos >= len(self._string): 54 | raise ParseStreamError('Unexpected end of string', self) 55 | return True 56 | -------------------------------------------------------------------------------- /avatar/bintools/gdb/readme.txt: -------------------------------------------------------------------------------- 1 | The code in this module is just a starting investigation... -------------------------------------------------------------------------------- /avatar/bintools/gdb/rsp.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | import socket 3 | from threading import Thread 4 | from queue import Queue 5 | from logging import debug, info, basicConfig, DEBUG 6 | 7 | 8 | class RemoteException(Exception): 9 | pass 10 | 11 | 12 | class GdbRemoteSerialProtocol(Thread): 13 | def __init__(self, host='localhost', port=1212): 14 | self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 15 | self.socket.connect((host,port)) 16 | 17 | def __chk(self,pkt): 18 | sum = 0 19 | for c in pkt: 20 | sum += ord(c) 21 | return sum & 0xff 22 | 23 | def __send(self, msg): 24 | debug('[GDB][TX] %s' % msg) 25 | self.socket.send(msg) 26 | 27 | def __recv(self, n): 28 | r = self.socket.recv(n) 29 | debug('[GDB][RX] %s' % r) 30 | return r 31 | 32 | def __expect_ack(self): 33 | reply = self.socket.recv(1) 34 | if reply != '+': 35 | raise RemoteException('Wrong ack: "%s"'% str(reply)) 36 | 37 | def __send_ack(self): 38 | self.__send('+') 39 | 40 | def __send_msg(self, msg): 41 | self.__send('$%s#%02x' % (msg, self.__chk(msg))) 42 | self.__expect_ack() 43 | 44 | def __recv_msg(self): 45 | c = self.socket.recv(1) 46 | if c != '$': 47 | raise RemoteException('Expected "$" received: "%s"' % str(c)) 48 | 49 | msg = '' 50 | while True: 51 | c = self.socket.recv(1) 52 | if c == '#': break 53 | msg += c 54 | 55 | chk = int(self.socket.recv(2), 16) 56 | if chk != self.__chk(msg): 57 | raise RemoteException('Wrong checksum') 58 | debug('[GDB][RX] $%s#%02x' % (msg, chk)) 59 | 60 | self.__send_ack() 61 | 62 | return msg 63 | 64 | def __del__(self): 65 | try: 66 | self.close() 67 | except: 68 | # close() most likely already called 69 | pass 70 | 71 | def close(self): 72 | self.__send_msg('k') 73 | self.socket.close() 74 | 75 | def cont(self, addr=None): 76 | pkt = 'c' 77 | if addr != None: 78 | pkt += '%x' % (addr) 79 | self.__send_msg(pkt) 80 | 81 | def step(self, addr=None): 82 | pkt = 's' 83 | if addr != None: 84 | pkt += '%x' % (addr) 85 | self.__send_msg(pkt) 86 | 87 | def __z_packet(self, pkt): 88 | self.__send_msg(pkt) 89 | reply = self.__recv_msg() 90 | if reply == '': 91 | info('Z packets are not supported by target.') 92 | else: 93 | if (reply != 'OK'): 94 | raise RemoteException('Unexpected reply: %s' % str(reply)) 95 | 96 | def break_insert(self, addr, _len=0, _type=0): 97 | self.__z_packet('Z%d,%x,%x' % (_type, addr, _len)) 98 | 99 | def break_remove(self, addr, _len=0, _type=0): 100 | self.__z_packet('z%d,%x,%x' % (_type, addr, _len)) 101 | 102 | def expect_signal(self): 103 | msg = self.__recv_msg() 104 | assert len(msg) == 3 and msg[0] == 'S', 'Expected "S", received "%c" % msg[0]' 105 | 106 | return int(msg[1:], 16) 107 | 108 | 109 | if __name__ == '__main__': 110 | basicConfig(level=DEBUG, format='%(levelname)-8s %(message)s') 111 | remote = GdbRemoteSerialProtocol() 112 | 113 | -------------------------------------------------------------------------------- /avatar/call_proxy.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Jun 24, 2013 3 | 4 | @author: Jonas Zaddach 5 | ''' 6 | 7 | from collections import defaultdict 8 | 9 | class EmulatorTargetCallProxy(): 10 | MONITOR_EVENTS = ["emulator_pre_read_request", 11 | "emulator_post_read_request", 12 | "emulator_pre_write_request", 13 | "emulator_post_write_request"] 14 | 15 | def __init__(self): 16 | self._target = None 17 | self._monitor_hooks = defaultdict(list) 18 | 19 | def set_target(self, target): 20 | self._target = target 21 | 22 | def add_monitor(self, monitor): 23 | for monitor_event in self.MONITOR_EVENTS: 24 | if hasattr(monitor, monitor_event): 25 | self._monitor_hooks[monitor_event].append(monitor) 26 | 27 | def remove_monitor(self, monitor): 28 | for (_, monitor_hooks) in self._monitor_hooks.items(): 29 | try: 30 | monitor_hooks.remove(monitor) 31 | except ValueError: 32 | pass 33 | 34 | def handle_emulator_read_request(self, params): 35 | assert(self._target) 36 | 37 | for monitor in self._monitor_hooks["emulator_pre_read_request"]: 38 | monitor.emulator_pre_read_request(params) 39 | 40 | params["value"] = self._target.read_typed_memory(params["address"], params["size"]) 41 | 42 | for monitor in self._monitor_hooks["emulator_post_read_request"]: 43 | monitor.emulator_post_read_request(params) 44 | 45 | return params["value"] 46 | 47 | def handle_emulator_write_request(self, params): 48 | assert(self._target) 49 | 50 | for monitor in self._monitor_hooks["emulator_pre_write_request"]: 51 | monitor.emulator_pre_write_request(params) 52 | 53 | self._target.write_typed_memory(params["address"], params["size"], params["value"]) 54 | 55 | for monitor in self._monitor_hooks["emulator_post_write_request"]: 56 | monitor.emulator_post_write_request(params) 57 | 58 | def handle_emulator_set_cpu_state_request(self, params): 59 | # this function sets the CPU state on the target device 60 | assert(self._target) 61 | 62 | # TODO: fire events? 63 | 64 | for reg in params["cpu_state"]: 65 | if reg == "cpsr": 66 | # skip cpsr register 67 | continue 68 | value = int(params["cpu_state"][reg], 16) 69 | self._target.set_register(reg, value) 70 | 71 | def handle_emulator_get_cpu_state_request(self, params): 72 | # this function gets the CPU state on the target device 73 | assert(self._target) 74 | 75 | # TODO: fire events? 76 | ret = {} 77 | 78 | for r in range(13): 79 | val = self._target.get_register("r"+str(r)) 80 | ret["cpu_state_"+"r"+str(r)] = hex(val) 81 | val = self._target.get_register("sp") 82 | ret["cpu_state_r13"] = hex(val) 83 | val = self._target.get_register("lr") 84 | ret["cpu_state_r14"] = hex(val) 85 | val = self._target.get_register("pc") 86 | ret["cpu_state_pc"] = hex(val) 87 | return ret 88 | 89 | def handle_emulator_continue_request(self, params): 90 | assert(self._target) 91 | 92 | self._target.cont() 93 | 94 | def handle_emulator_get_checksum_request(self, params): 95 | assert(self._target) 96 | 97 | cmd = "-gdb-show remote checksum %s %s" % \ 98 | (hex(params['address'])[2:], params['size'][2:]) 99 | return self._target.execute_gdb_command(cmd) 100 | #return self._target.get_checksum(\ 101 | # params['address'], params['size']) 102 | 103 | -------------------------------------------------------------------------------- /avatar/debuggable.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on May 3, 2013 3 | 4 | @author: Jonas Zaddach 5 | ''' 6 | 7 | class Breakpoint(): 8 | """This is an interface for breakpoints that are created by Debuggable.set_breakpoint""" 9 | def __init__(self): 10 | self._handler = None 11 | 12 | def wait(self): 13 | """Wait until this breakpoint is hit""" 14 | assert(False) #Not implemented 15 | 16 | def delete(self): 17 | """Delete this breakpoint""" 18 | assert(False) #Not implemented 19 | 20 | def set_handler(self, handler): 21 | """Set the handler function that is called when the breakpoint is hit""" 22 | self._handler = handler 23 | 24 | 25 | class Debuggable(): 26 | """This is an interface for all objects that support a minimal set of debugging operations""" 27 | def read_typed_memory(self, address, size): 28 | """Read a memory word with size size from memory address 29 | address""" 30 | assert(False) #No implementation 31 | 32 | def write_typed_memory(self, address, size, value): 33 | """Write a memory word val with size size to memory address 34 | address""" 35 | assert(False) #No implementation 36 | 37 | def read_untyped_memory(self, address, length): 38 | """Read a range of untyped (byte) memory""" 39 | data = [] 40 | for i in range(0, length): 41 | data.append(self.read_typed_memory(address + i, 1)) 42 | 43 | return bytes(data) 44 | 45 | def write_untyped_memory(self, address, data): 46 | """Write untyped (byte) data""" 47 | for byte in data: 48 | self.write_typed_memory(address, 1, byte) 49 | address += 1 50 | 51 | def get_register(self, register): 52 | """Return the value of a register""" 53 | assert(False) #No implementation 54 | 55 | def set_register(self, register, value): 56 | """Set the value of a register""" 57 | assert(False) #No implementation 58 | 59 | def set_breakpoint(self, address, **properties): 60 | """ 61 | Set a code breakpoint. 62 | Properties can be: 63 | - temporary (boolean): If True, breakpoint is deleted upon hit 64 | - thumb (boolean): If True and architecture is arm, a thumb 65 | breakpoint will be used. 66 | """ 67 | assert(False) #Not implemented 68 | 69 | def remove_breakpoint(self, address): 70 | """Remove a breakpoint""" 71 | assert(False) #Not implemented 72 | 73 | def dump_registers(self): 74 | """Dump the value of general registers""" 75 | assert(False) #No implementation 76 | 77 | def dump_all_registers(self): 78 | """Dump the value of all registers""" 79 | assert(False) #No implementation 80 | 81 | def cont(self): 82 | """Continue execution""" 83 | assert(False) #No implementation 84 | 85 | def halt(self): 86 | """Continue execution""" 87 | assert(False) #No implementation 88 | 89 | #TODO: Merge with set_breakpoint 90 | def put_bp(self, addr): 91 | """Put a breakpoint""" 92 | assert(False) #No implementation 93 | 94 | #TODO: Merge with remove_bp 95 | def remove_bp(self, addr): 96 | """Remove a breakpoint""" 97 | assert(False) #No implementation 98 | -------------------------------------------------------------------------------- /avatar/emulators/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avatarone/avatar-python/c6d74f85f63333e3031e1f5e208d3f90e316a9e4/avatar/emulators/__init__.py -------------------------------------------------------------------------------- /avatar/emulators/emulator.py: -------------------------------------------------------------------------------- 1 | from avatar.debuggable import Debuggable 2 | from avatar.system import EVENT_REQUEST_WRITE_MEMORY_VALUE,\ 3 | EVENT_REQUEST_READ_MEMORY_VALUE 4 | 5 | class Emulator(Debuggable): 6 | def __init__(self, system): 7 | super(Emulator, self).__init__() 8 | self._system = system 9 | self._read_handler = None 10 | self._write_handler = None 11 | self._set_cpu_state_handler = None 12 | self._get_cpu_state_handler = None 13 | self._continue_handler = None 14 | self._get_checksum_handler = None 15 | 16 | def set_read_request_handler(self, handler): 17 | self._read_handler = handler 18 | 19 | def set_write_request_handler(self, handler): 20 | self._write_handler = handler 21 | 22 | def set_set_cpu_state_request_handler(self, handler): 23 | self._set_cpu_state_handler = handler 24 | 25 | def set_get_cpu_state_request_handler(self, handler): 26 | self._get_cpu_state_handler = handler 27 | 28 | def set_continue_request_handler(self, handler): 29 | self._continue_handler = handler 30 | 31 | def set_get_checksum_request_handler(self, handler): 32 | self._get_checksum_handler = handler 33 | 34 | def _notify_read_request_handler(self, params): 35 | self._system.post_event({"source": "emulator", 36 | "tags": [EVENT_REQUEST_READ_MEMORY_VALUE], 37 | "properties": params}) 38 | assert(self._read_handler) #Read handler must be set at this point 39 | 40 | return self._read_handler(params) 41 | 42 | def _notify_write_request_handler(self, params): 43 | self._system.post_event({"source": "emulator", 44 | "tags": [EVENT_REQUEST_WRITE_MEMORY_VALUE], 45 | "properties": params}) 46 | assert(self._write_handler) #Write handler must be set at this point 47 | 48 | return self._write_handler(params) 49 | 50 | def _notify_set_cpu_state_handler(self, params): 51 | # TODO: we don't have a notify event 52 | assert(self._set_cpu_state_handler) 53 | 54 | return self._set_cpu_state_handler(params) 55 | 56 | def _notify_get_cpu_state_handler(self, params): 57 | # TODO: we don't have a notify event 58 | assert(self._get_cpu_state_handler) 59 | 60 | return self._get_cpu_state_handler(params) 61 | 62 | def _notify_continue_handler(self, params): 63 | # TODO: we don't have a notify event 64 | assert(self._continue_handler) 65 | 66 | return self._continue_handler(params) 67 | 68 | def _notify_get_checksum_handler(self, params): 69 | # TODO: we don't have a notify event 70 | assert(self._get_checksum_handler) 71 | 72 | return self._get_checksum_handler(params) 73 | 74 | -------------------------------------------------------------------------------- /avatar/emulators/null_emulator.py: -------------------------------------------------------------------------------- 1 | from avatar.emulators.s2e.configuration import S2EConfiguration 2 | import logging 3 | import subprocess 4 | import os 5 | from avatar.emulators.emulator import Emulator 6 | from queue import Queue 7 | log = logging.getLogger(__name__) 8 | 9 | 10 | class NullEmulator(Emulator): 11 | def __init__(self, system): 12 | super().__init__(system) 13 | 14 | def init(self): 15 | pass 16 | 17 | def start(self): 18 | pass 19 | 20 | def stop(self): 21 | pass 22 | 23 | def exit(self): 24 | pass 25 | 26 | def write_typed_memory(self, address, size, data): 27 | pass 28 | 29 | def set_register(self, reg, val): 30 | pass 31 | 32 | def get_register(self, reg): 33 | return None 34 | 35 | def set_breakpoint(self, address, **properties): 36 | pass 37 | 38 | def cont(self): 39 | pass 40 | 41 | def init_null_emulator(system): 42 | system.set_emulator(NullEmulator(system)) 43 | 44 | 45 | -------------------------------------------------------------------------------- /avatar/emulators/s2e/__init__.py: -------------------------------------------------------------------------------- 1 | from avatar.emulators.s2e.s2e_emulator import S2EEmulator 2 | 3 | def init_s2e_emulator(system): 4 | system.set_emulator(S2EEmulator(system)) -------------------------------------------------------------------------------- /avatar/emulators/s2e/debug_s2e_emulator.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Jun 26, 2013 3 | 4 | @author: Jonas Zaddach 5 | ''' 6 | from avatar.emulators.s2e.s2e_emulator import S2EEmulator 7 | import logging 8 | import subprocess 9 | import time 10 | import os.path 11 | from avatar.interfaces.s2e_remote_memory import S2ERemoteMemoryInterface 12 | 13 | 14 | log = logging.getLogger(__name__) 15 | 16 | 17 | class DebugS2EEmulator(S2EEmulator): 18 | def __init__(self, system): 19 | system.get_configuration()["avatar_configuration"] = system.get_configuration()["avatar_configuration"] or {} 20 | system.get_configuration()["avatar_configuration"]["s2e_debug"] = True 21 | super().__init__(system) 22 | 23 | def run_s2e_process(self): 24 | try: 25 | log.info("Starting QEMU with S2E process: %s", " ".join(["'%s'" % x for x in self._cmdline])) 26 | gdb_file = os.path.join(self._configuration.get_output_directory(), "run.gdb") 27 | 28 | f = open(gdb_file, 'w') 29 | f.write("break main\n") 30 | f.write("run %s\n" % " ".join(["'%s'" % x for x in self._cmdline[1:]])) 31 | f.close() 32 | 33 | #TODO: get gdb program from config 34 | self._s2e_process = subprocess.Popen(["gdb", "-x", gdb_file, self._cmdline[0]], 35 | cwd = self._configuration.get_output_directory()) 36 | 37 | self._remote_memory_interface = S2ERemoteMemoryInterface(self._configuration.get_remote_memory_listen_address()) 38 | self._remote_memory_interface.set_read_handler(self._notify_read_request_handler) 39 | self._remote_memory_interface.set_write_handler(self._notify_write_request_handler) 40 | time.sleep(20) #Wait a bit for the S2E process to start 41 | self._remote_memory_interface.start() 42 | 43 | self._s2e_process.wait() 44 | except KeyboardInterrupt: 45 | pass 46 | 47 | self.exit() 48 | 49 | def init_debug_s2e_emulator(system): 50 | system.set_emulator(DebugS2EEmulator(system)) -------------------------------------------------------------------------------- /avatar/interfaces/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avatarone/avatar-python/c6d74f85f63333e3031e1f5e208d3f90e316a9e4/avatar/interfaces/__init__.py -------------------------------------------------------------------------------- /avatar/interfaces/avatar_stub/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avatarone/avatar-python/c6d74f85f63333e3031e1f5e208d3f90e316a9e4/avatar/interfaces/avatar_stub/__init__.py -------------------------------------------------------------------------------- /avatar/interfaces/avatar_stub/avatar_exceptions.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on May 2, 2013 3 | 4 | @author: Jonas Zaddach 5 | ''' 6 | class AvatarException(Exception): 7 | def __init__(self, reason = None): 8 | self._reason = reason 9 | 10 | def __str__(self): 11 | if self._reason: 12 | return "Avatar exception: %s" % self._reason 13 | else: 14 | return "Avatar exception" 15 | 16 | class AvatarUnimplementedException(AvatarException): 17 | def __init(self): 18 | super().__init__("Unimplemented") 19 | 20 | class AvatarNotSupportedException(AvatarException): 21 | def __init__(self): 22 | super().__init__("Not supported") 23 | 24 | class AvatarConnectException(AvatarException): 25 | def __init__(self, msg): 26 | super().__init__("Connect error: " + msg) 27 | 28 | class AvatarRemoteError(AvatarException): 29 | def __init__(self, code): 30 | super().__init__("Stub error") 31 | self._code = code 32 | 33 | def __str__(self): 34 | return super.__str__() + " (error code 0x%02x)" % self._code 35 | 36 | class AvatarProtocolUnknownOpcodeException(AvatarException): 37 | def __init__(self, opcode): 38 | self.opcode = opcode 39 | 40 | def __repr__(self): 41 | return "Error: Unknown opcode 0x%02x" % self.opcode 42 | 43 | class AvatarProtocolOutOfDataException(AvatarException): 44 | def __init__(self, err): 45 | self.index_error = err 46 | 47 | def __repr__(self): 48 | return "Error: Invalid data index access (%s)" % (str(self.index_error)) -------------------------------------------------------------------------------- /avatar/interfaces/avatar_stub/avatar_protocol.py: -------------------------------------------------------------------------------- 1 | import threading 2 | import logging 3 | from queue import Queue, Empty 4 | from avatar.util.reference import Reference 5 | from avatar.interfaces.avatar_stub.avatar_protocol_lowlevel import AvatarLowlevelProtocol 6 | from avatar.interfaces.avatar_stub.avatar_messages import create_avatar_message 7 | from avatar.interfaces.avatar_stub.avatar_exceptions import AvatarRemoteError 8 | 9 | 10 | log = logging.getLogger(__name__) 11 | 12 | 13 | ASYNCHRONOUS_MESSAGES = ["AVATAR_RPC_DTH_STATE", "AVATAR_RPC_DTH_PAGEFAULT", "AVATAR_RPC_DTH_INFO_EXCEPTION"] 14 | RESPONSE_TIMEOUT = 10 15 | 16 | class AvatarProtocol(): 17 | CONNECT_TIMEOUT = 10 18 | def __init__(self, sock, paging_handler = lambda x: None): 19 | #TODO: Put a meaningful timeout 20 | self._socket = sock 21 | self._protocol = AvatarLowlevelProtocol(self._socket, self._handle_received_message) 22 | 23 | self._terminate = threading.Event() 24 | self._state = None 25 | self._asynchronous_messages_handler = paging_handler 26 | self._queued_commands = Queue() 27 | self._received_synchronous_messages = Queue() 28 | self._send_thread = threading.Thread(target = self.run_send) 29 | self._send_lock = threading.Lock() 30 | self._send_thread.start() 31 | 32 | def _handle_received_message(self, msg): 33 | if msg.name in ASYNCHRONOUS_MESSAGES: 34 | self.handle_asynchronous_message(msg) 35 | else: 36 | self._received_synchronous_messages.put(msg) 37 | 38 | def run_send(self): 39 | while not self._terminate.is_set(): 40 | result = None 41 | try: 42 | result = self._queued_commands.get(timeout = 1) 43 | except Empty: 44 | continue 45 | 46 | if not result: 47 | continue 48 | 49 | self._send_lock.acquire() 50 | self._protocol.send_message(result[0]) 51 | self._send_lock.release() 52 | 53 | if result[1]: 54 | log.debug("Waiting for response to message %s", result[0].name) 55 | recv_msg = self._received_synchronous_messages.get(timeout = RESPONSE_TIMEOUT) 56 | if recv_msg and recv_msg.name in result[1]: 57 | if result[2]: 58 | result[2].acquire() 59 | if result[3]: 60 | result[3].set_value(recv_msg) 61 | result[2].notify() 62 | result[2].release() 63 | else: 64 | log.warn("Unexpected message received: %s", recv_msg.name) 65 | 66 | def handle_asynchronous_message(self, msg): 67 | if msg.name == "AVATAR_RPC_DTH_PAGEFAULT": 68 | page_data = self._page_fault_handler(msg.page_address) 69 | self.insert_page(msg.page_address, page_data) 70 | self._send_lock.acquire() 71 | self._protocol.send_message(create_avatar_message("AVATAR_RPC_HTD_CONTINUE_FROM_PAGEFAULT", {})) 72 | self._send_lock.release() 73 | elif msg.name == "AVATAR_RPC_DTH_STATE": 74 | self._state = msg.state 75 | 76 | elif msg.name == "AVATAR_RPC_DTH_INFO_EXCEPTION": 77 | self._exception_handler(msg.exception) 78 | self._asynchronous_messages_handler(msg) 79 | 80 | def set_register(self, register, value): 81 | msg = create_avatar_message("AVATAR_RPC_HTD_SET_REGISTER", {"register": register, "value": value}) 82 | expected_replies = ["AVATAR_RPC_DTH_REPLY_OK", "AVATAR_RPC_DTH_REPLY_ERROR"] 83 | cv = threading.Condition() 84 | ref = Reference() 85 | 86 | cv.acquire() 87 | self._queued_commands.put((msg, expected_replies, cv, ref)) 88 | cv.wait() 89 | cv.release() 90 | 91 | def get_register(self, register): 92 | msg = create_avatar_message("AVATAR_RPC_HTD_GET_REGISTER", {"register": register}) 93 | expected_replies = ["AVATAR_RPC_DTH_REPLY_GET_REGISTER", "AVATAR_RPC_DTH_REPLY_ERROR"] 94 | cv = threading.Condition() 95 | ref = Reference() 96 | 97 | cv.acquire() 98 | self._queued_commands.put((msg, expected_replies, cv, ref)) 99 | cv.wait() 100 | cv.release() 101 | if ref.get_value().name == "AVATAR_RPC_DTH_REPLY_ERROR": 102 | raise AvatarRemoteError(ref.get_value().error) 103 | return ref.get_value().value 104 | 105 | def read_memory(self, address, size): 106 | msg = create_avatar_message("AVATAR_RPC_HTD_READ_MEMORY", {"address": address, "size": size}) 107 | expected_replies = ["AVATAR_RPC_DTH_REPLY_READ_MEMORY", "AVATAR_RPC_DTH_REPLY_ERROR"] 108 | cv = threading.Condition() 109 | ref = Reference() 110 | 111 | cv.acquire() 112 | self._queued_commands.put((msg, expected_replies, cv, ref)) 113 | cv.wait() 114 | cv.release() 115 | if ref.get_value().name == "AVATAR_RPC_DTH_REPLY_ERROR": 116 | raise AvatarRemoteError(ref.get_value().error) 117 | 118 | return ref.get_value().value 119 | 120 | def write_memory(self, address, size, value): 121 | msg = create_avatar_message("AVATAR_RPC_HTD_WRITE_MEMORY", {"address": address, "size": size, "value": value}) 122 | expected_replies = ["AVATAR_RPC_DTH_REPLY_OK", "AVATAR_RPC_DTH_REPLY_ERROR"] 123 | cv = threading.Condition() 124 | ref = Reference() 125 | 126 | cv.acquire() 127 | self._queued_commands.put((msg, expected_replies, cv, ref)) 128 | cv.wait() 129 | cv.release() 130 | if ref.get_value().name == "AVATAR_RPC_DTH_REPLY_ERROR": 131 | raise AvatarRemoteError(ref.get_value().error) 132 | 133 | def read_memory_untyped(self, address, size): 134 | assert(size <= 255) 135 | msg = create_avatar_message("AVATAR_RPC_HTD_READ_UNTYPED_MEMORY", {"address": address, "size": size}) 136 | expected_replies = ["AVATAR_RPC_DTH_REPLY_READ_UNTYPED_MEMORY", "AVATAR_RPC_DTH_REPLY_ERROR"] 137 | cv = threading.Condition() 138 | ref = Reference() 139 | 140 | cv.acquire() 141 | self._queued_commands.put((msg, expected_replies, cv, ref)) 142 | cv.wait() 143 | cv.release() 144 | if ref.get_value().name == "AVATAR_RPC_DTH_REPLY_ERROR": 145 | raise AvatarRemoteError(ref.get_value().error) 146 | 147 | return ref.get_value().data 148 | 149 | def write_memory_untyped(self, address, data): 150 | assert(len(data) <= 255) 151 | assert(isinstance(data, bytes)) 152 | msg = create_avatar_message("AVATAR_RPC_HTD_WRITE_UNTYPED_MEMORY", {"address": address, "data": data}) 153 | expected_replies = ["AVATAR_RPC_DTH_REPLY_OK", "AVATAR_RPC_DTH_REPLY_ERROR"] 154 | cv = threading.Condition() 155 | ref = Reference() 156 | 157 | cv.acquire() 158 | self._queued_commands.put((msg, expected_replies, cv, ref)) 159 | cv.wait() 160 | cv.release() 161 | if ref.get_value().name == "AVATAR_RPC_DTH_REPLY_ERROR": 162 | raise AvatarRemoteError(ref.get_value().error) 163 | 164 | def execute_codelet(self, address): 165 | msg = create_avatar_message("AVATAR_RPC_HTD_CODELET_EXECUTE", {"address": address}) 166 | expected_replies = ["AVATAR_RPC_DTH_REPLY_CODELET_EXECUTION_FINISHED", "AVATAR_RPC_DTH_REPLY_ERROR"] 167 | cv = threading.Condition() 168 | ref = Reference() 169 | 170 | cv.acquire() 171 | self._queued_commands.put((msg, expected_replies, cv, ref)) 172 | cv.wait() 173 | cv.release() 174 | if ref.get_value().name == "AVATAR_RPC_DTH_REPLY_ERROR": 175 | raise AvatarRemoteError(ref.get_value().error) 176 | 177 | def cont(self): 178 | msg = create_avatar_message("AVATAR_RPC_HTD_RESUME_VM", {}) 179 | expected_replies = ["AVATAR_RPC_DTH_REPLY_OK", "AVATAR_RPC_DTH_REPLY_ERROR"] 180 | cv = threading.Condition() 181 | ref = Reference() 182 | 183 | cv.acquire() 184 | self._queued_commands.put((msg, expected_replies, cv, ref)) 185 | cv.wait() 186 | cv.release() 187 | if ref.get_value().name == "AVATAR_RPC_DTH_REPLY_ERROR": 188 | raise AvatarRemoteError(ref.get_value().error) 189 | 190 | def stop(self): 191 | self._terminate.set() 192 | self._protocol.stop() 193 | 194 | -------------------------------------------------------------------------------- /avatar/interfaces/avatar_stub/avatar_protocol_lowlevel.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import threading 4 | from select import select 5 | import time 6 | from avatar.util.indexable_queue import IndexableQueue 7 | from avatar.util.checksum import Crc8 8 | import logging 9 | from functools import reduce 10 | from avatar.interfaces.avatar_stub.avatar_messages import parse_avatar_message 11 | 12 | log = logging.getLogger(__name__) 13 | 14 | class AvatarLowlevelProtocol(): 15 | """ 16 | Encapsulates the communication between the avatar server and the 17 | avatar stub. 18 | """ 19 | 20 | 21 | 22 | def __init__(self, sock, message_handler): 23 | """ 24 | Initialize the protocol. 25 | @param input_stream Stream from stub to avatar server. 26 | @param output_stream Stream from avatar server to stub. 27 | """ 28 | self._socket = sock 29 | self.input_buffer = [] 30 | self.condition = threading.Condition() 31 | self.messages = IndexableQueue() 32 | self.terminate = threading.Event() 33 | self.thread = threading.Thread(target = self.run) 34 | self.thread.start() 35 | self._received_message_handler = message_handler 36 | 37 | def run(self): 38 | while not self.terminate.is_set(): 39 | (rd, _, _) = select([self._socket], [], [], 1) 40 | if not rd: 41 | continue 42 | 43 | next_byte = self._socket.recv(1) 44 | 45 | if next_byte[0] == 0x55: #End message marker 46 | joined_buffer = reduce(lambda r, x: r + x, self.input_buffer, bytes()) 47 | log.debug("Received raw message %s", "".join( 48 | ["%02x" % x for x in joined_buffer])) 49 | self.parse_message(joined_buffer) 50 | self.input_buffer = [] 51 | else: 52 | if next_byte[0] == 0xAA: 53 | #There has to be a following byte for the escape byte 54 | #TODO: do something to prevent program from hanging here 55 | # if input is not protocol conformant 56 | next_next_byte = self._socket.recv(1) 57 | if next_next_byte[0] == 0x01: 58 | next_byte = bytes([0x55]) 59 | elif next_next_byte[0] == 0x02: 60 | next_byte = bytes([0xAA]) 61 | else: 62 | #TODO: Error, escape sequence unknown 63 | pass 64 | self.input_buffer.append(next_byte) 65 | 66 | def send_message(self, avatar_message): 67 | serialized_message = avatar_message.serialize() 68 | 69 | log.info("Sending message %s" % str(avatar_message)) 70 | log.debug("Sending serialized message %s", "".join(["%02x" % x for x in serialized_message])) 71 | escaped_message = serialized_message.replace(bytes([0xAA]), bytes([0xAA, 0x02])). \ 72 | replace(bytes([0x55]), bytes([0xAA, 0x01])) 73 | crc = Crc8(serialized_message).get_crc() 74 | escaped_crc = bytes([crc & 0xFF]).replace(bytes([0xAA]), bytes([0xAA, 0x02])). \ 75 | replace(bytes([0x55]), bytes([0xAA, 0x01])) 76 | raw_message = escaped_message + escaped_crc + bytes([0x55]) 77 | self._socket.send(raw_message) 78 | log.debug("Sending raw message %s", "".join(["%02x" % x for x in raw_message])) 79 | 80 | def parse_message(self, data): 81 | if not data: 82 | return 83 | message_crc = data[-1] 84 | calculated_crc = Crc8(data[:-1]).get_crc() 85 | 86 | if message_crc != calculated_crc: 87 | log.warn("Message 0x%02x CRC 0x%02x != calculated CRC 0x%02x", \ 88 | data[0], message_crc, calculated_crc) 89 | return 90 | 91 | try: 92 | message = parse_avatar_message(data) 93 | if message: 94 | log.info("Received message %s", str(message)) 95 | self._received_message_handler(message) 96 | # self.messages.put(message) 97 | # self.condition.acquire() 98 | # self.condition.notify_all() 99 | # self.condition.release() 100 | except Exception: 101 | log.exception("Error parsing received message") 102 | 103 | # def receive_message_blocking(self, timeout = -1, message_type = None): 104 | # if message_type: 105 | # start_time = time.time() 106 | # 107 | # self.condition.acquire() 108 | # while True: 109 | # msg = self.messages.find_and_remove( 110 | # lambda x: x.name == message_type) 111 | # if msg: 112 | # self.condition.release() 113 | # return msg 114 | # 115 | # if timeout != -1 and time.time() - start_time >= timeout: 116 | # self.condition.release() 117 | # return None 118 | # 119 | # self.condition.wait(timeout) 120 | # else: 121 | # return self.messages.get(timeout) 122 | 123 | def stop(self): 124 | self.terminate.set() -------------------------------------------------------------------------------- /avatar/interfaces/gdb/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avatarone/avatar-python/c6d74f85f63333e3031e1f5e208d3f90e316a9e4/avatar/interfaces/gdb/__init__.py -------------------------------------------------------------------------------- /avatar/interfaces/gdb/avatar_gdb_bridge.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avatarone/avatar-python/c6d74f85f63333e3031e1f5e208d3f90e316a9e4/avatar/interfaces/gdb/avatar_gdb_bridge.py -------------------------------------------------------------------------------- /avatar/interfaces/gdb/errors.py: -------------------------------------------------------------------------------- 1 | class ProtocolError(Exception): 2 | def __init__(self, description): 3 | self.description = description 4 | 5 | class ProtocolUnknownOpcodeError(ProtocolError): 6 | def __init__(self, opcode): 7 | self.opcode = opcode 8 | 9 | def __repr__(self): 10 | return "Error: Unknown opcode 0x%02x" % self.opcode 11 | 12 | class ProtocolOutOfDataError(ProtocolError): 13 | def __init__(self, err): 14 | self.index_error = err 15 | 16 | def __repr__(self): 17 | return "Error: Invalid data index access (%s)" % (str(self.index_error)) -------------------------------------------------------------------------------- /avatar/interfaces/gdb/gdb_server.py: -------------------------------------------------------------------------------- 1 | from avatar.debuggable import Debuggable 2 | from avatar.interfaces.gdb.protocol_lowlevel import GdbLowlevelProtocol 3 | import socket 4 | import struct 5 | 6 | import logging 7 | log = logging.getLogger(__name__) 8 | 9 | class InvalidChecksumException(Exception): 10 | pass 11 | 12 | class GdbServer: 13 | def __init__(self, debuggable, sock, system, verbose=False): 14 | self._verbose=verbose 15 | self._debuggable = debuggable 16 | self._socket = sock 17 | self._low_level_protocol = GdbLowlevelProtocol(sock, self._message_received, verbose=self._verbose) 18 | self._low_level_protocol.start() 19 | self._system=system 20 | self._system.register_event_listener(self.handle_event) 21 | self._breakpoints = {} 22 | 23 | def handle_event(self, evt): 24 | # TODO this is very very verbose ... 25 | if self._verbose: 26 | log.info("gdb_server handle_event recieved : %s", evt) 27 | if 'EVENT_BREAKPOINT' in evt['tags'] or 'EVENT_END_STEPPING' in evt['tags'] : 28 | self._low_level_protocol.send_message("S05") 29 | 30 | def _message_received(self, msg): 31 | if self._verbose: print("Received message: %s" % msg) 32 | opcode = msg[0] 33 | if opcode == 'm': 34 | address = int(msg[1:].split(',')[0], 16) 35 | size = int(msg[1:].split(',')[1]) 36 | if size in [1, 2, 4]: 37 | value = self._debuggable.read_typed_memory(address, size) 38 | self._low_level_protocol.send_message("".join(["%02x" % x for x in struct.pack("<%s" % {1: "B", 2: "H", 4: "L"}[size], value)])) 39 | else: 40 | value = self._debuggable.read_untyped_memory(address, size) 41 | self._low_level_protocol.send_message("".join(["%02x" % x for x in value])) 42 | elif opcode == 'M': 43 | address_size = msg[1:].split(":")[0] 44 | address = int(address_size.split(",")[0], 16) 45 | size = int(address_size.split(",")[1], 16) 46 | data = bytes([int("".join(x), 16) for x in zip(*[iter(msg[1:].split(":")[1])] * 2)]) 47 | 48 | assert(len(data) == size) 49 | 50 | if size in [1, 2, 4]: 51 | (value, ) = struct.unpack("<%s" % {1: "B", 2: "H", 4: "L"}[size], data) 52 | self._debuggable.write_typed_memory(address, size, value) 53 | else: 54 | self._debuggable.write_untyped_memory(address, data) 55 | #TODO: On error reply with error message 56 | self._low_level_protocol.send_message("OK") 57 | elif opcode == 'g': 58 | #TODO: ARM specific 59 | registers = ["r0", "r1", "r2", "r3", "r4", "r5", 60 | "r6", "r7", "r8", "r9", "r10", 61 | "r11", "r12", "sp", "lr", "pc", "cpsr"] 62 | register_values = [self._debuggable.get_register(x) for x in registers] 63 | data = "".join(["".join(["%02x" % y for y in struct.pack("L", value_wrong_endianness))[0] 82 | self._debuggable.set_register(regnr, value) 83 | self._low_level_protocol.send_message("OK") 84 | elif opcode == 'c': 85 | self._debuggable.cont() 86 | elif opcode == 'z': 87 | tipe = ord(msg[1]) - ord('0') 88 | address = int(msg[1:].split(",")[1], 16) 89 | kind = msg[1:].split(",")[2] 90 | if tipe in [0, 1]: 91 | self._breakpoints[address].delete() 92 | del self._breakpoints[address] 93 | # self._debuggable.clear_breakpoint(address, ) 94 | else: 95 | assert(False) #Unimplemented break/watchpoint type 96 | self._low_level_protocol.send_message("OK") 97 | elif opcode == 'Z': 98 | tipe = ord(msg[1]) - ord('0') 99 | address = int(msg[1:].split(",")[1], 16) 100 | kind = msg[1:].split(",")[2] 101 | if tipe in [0, 1]: 102 | bkpt = self._debuggable.set_breakpoint(address) 103 | self._breakpoints[address] = bkpt 104 | else: 105 | assert(False) #Unimplemented break/watchpoint type 106 | self._low_level_protocol.send_message("OK") 107 | elif opcode == '?': 108 | #TODO: Return real state instead of dummy 109 | self._low_level_protocol.send_message("S05") 110 | elif opcode == 's': 111 | self._debuggable.stepi() 112 | elif opcode in ['v','q','H']: 113 | log.info("gdb opcode '%s' not supported, but should be ok"% opcode) 114 | self._low_level_protocol.send_message("") 115 | else : 116 | log.error("gdb_server.py: unknown gdb opcode '%s' (not implemented?)"% opcode) 117 | self._low_level_protocol.send_message("") 118 | 119 | class TestDebuggable(Debuggable): 120 | def read_typed_memory(self, address, size): 121 | print("Called read_typed_memory(0x%08x, %d)" % (address, size)) 122 | return 0xcafebabe & (0xFFFFFFFF >> (8 * (4 - size))) 123 | 124 | def write_typed_memory(self, address, size, value): 125 | print("Called write_typed_memory(0x%08x, %d, 0x%08x)" % (address, size, value)) 126 | 127 | def read_untyped_memory(self, address, length): 128 | print("Called read_untyped_memory(0x%08x, %d)" % (address, length)) 129 | return bytes([0xfe] * length) 130 | 131 | def write_untyped_memory(self, address, data): 132 | print("Called write_untyped_memory(0x%08x, %s)" % (address, ".".join(["%02x" % x for x in data]))) 133 | 134 | def get_register(self, register): 135 | print("Called get_register(%s)" % str(register)) 136 | return 0xdeadbeef 137 | 138 | def set_register(self, register, value): 139 | print("Called set_register(%s, 0x%08x)" % (str(register), value)) 140 | 141 | def set_breakpoint(self, address, **properties): 142 | print("Called set_breakpoint(0x%08x)" % address) 143 | 144 | def clear_breakpoint(self, address, **properties): 145 | print("Called clear_breakpoint(0x%08x)" % address) 146 | 147 | def cont(self): 148 | print("Called cont") 149 | 150 | if __name__ == "__main__": 151 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 152 | sock.bind(("127.0.0.1", 5555)) 153 | sock.listen(1) 154 | (s, _) = sock.accept() 155 | print("GDB connected") 156 | gdb = GdbServer(TestDebuggable(), s) 157 | 158 | 159 | -------------------------------------------------------------------------------- /avatar/interfaces/gdb/protocol_lowlevel.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import threading 4 | import select 5 | import logging 6 | import functools 7 | 8 | log = logging.getLogger(__name__) 9 | 10 | START_OF_MESSAGE_MARKER = ord('$') 11 | END_OF_MESSAGE_MARKER = ord('#') 12 | 13 | HEX_CHARACTERS = bytes('0123456789ABCDEFabcdef', encoding = 'ascii') 14 | 15 | STATE_IDLE = 0 16 | STATE_IN_MESSAGE = 1 17 | STATE_IN_CHECKSUM_1 = 2 18 | STATE_IN_CHECKSUM_2 = 3 19 | 20 | 21 | class GdbLowlevelProtocol(): 22 | """ 23 | Encapsulates the communication between the avatar server and the 24 | avatar stub. 25 | """ 26 | 27 | 28 | 29 | def __init__(self, sock, received_message_handler, verbose=False): 30 | """ 31 | Initialize the protocol. 32 | @param input_stream Stream from stub to avatar server. 33 | @param output_stream Stream from avatar server to stub. 34 | """ 35 | self._verbose=verbose 36 | self._socket = sock 37 | self._received_message_handler = received_message_handler 38 | self._condition = threading.Condition() 39 | self._terminate = threading.Event() 40 | self._thread = threading.Thread(target = self.run) 41 | 42 | 43 | def start(self): 44 | self._thread.start() 45 | 46 | def run(self): 47 | state = STATE_IDLE 48 | message = [] 49 | received_checksum = 0 50 | 51 | while not self._terminate.is_set(): 52 | (rd, _, _) = select.select([self._socket], [], [], 1) 53 | if not rd: 54 | continue 55 | 56 | data = self._socket.recv(1024) 57 | if not data: 58 | continue 59 | 60 | for next_byte in data: 61 | # if next_byte == "\x03": 62 | # state = STATE_IDLE 63 | # message = [] 64 | # self._received_message_handler("ctrl-c") 65 | # log.warn("TODO: recieved interrupt, ctrl-c not fully handeled yet... ") 66 | if next_byte == START_OF_MESSAGE_MARKER: 67 | state = STATE_IN_MESSAGE 68 | message = [] 69 | elif state == STATE_IN_MESSAGE and next_byte == END_OF_MESSAGE_MARKER: 70 | state = STATE_IN_CHECKSUM_1 71 | elif state == STATE_IN_MESSAGE: 72 | message.append(next_byte) 73 | elif state == STATE_IN_CHECKSUM_1: 74 | assert(next_byte in HEX_CHARACTERS) 75 | received_checksum = (int(chr(next_byte), 16) << 4) & 0xF0 76 | state = STATE_IN_CHECKSUM_2 77 | elif state == STATE_IN_CHECKSUM_2: 78 | assert(next_byte in HEX_CHARACTERS) 79 | received_checksum |= int(chr(next_byte), 16) & 0x0F 80 | state = STATE_IDLE 81 | 82 | #Verify checksum 83 | calculated_checksum = functools.reduce(lambda r, x: (r + x) & 0xFF, message, 0) 84 | if self._verbose: 85 | print("Calculated checksum: %02x, received checksum: %02x" % (calculated_checksum, received_checksum)) 86 | if calculated_checksum == received_checksum: 87 | self._socket.send(bytes('+', encoding = 'ascii')) 88 | self._received_message_handler(bytes(message).decode('ascii')) 89 | else: 90 | self._socket.send(bytes('-', encoding = 'ascii')) 91 | 92 | def send_message(self, message): 93 | if self._verbose: 94 | print("Sending reply: '%s'" % message) 95 | raw_message = bytes(message, encoding = 'ascii') 96 | checksum = functools.reduce(lambda r, x: (r + x) & 0xFF, raw_message, 0) 97 | encoded_message = bytes('$', encoding = 'ascii') + \ 98 | raw_message + \ 99 | bytes('#%02x' % checksum, encoding = 'ascii') 100 | self._socket.send(encoded_message) 101 | -------------------------------------------------------------------------------- /avatar/interfaces/s2e_remote_memory.py: -------------------------------------------------------------------------------- 1 | import threading 2 | import logging 3 | import sys 4 | import json 5 | import socket 6 | import time 7 | from select import select 8 | 9 | log = logging.getLogger("avatar.remote_memory_interface") 10 | 11 | class RemoteMemoryInterface(object): 12 | def __init__(self): 13 | self._read_handler = None 14 | self._write_handler = None 15 | self._set_cpu_state_handler = None 16 | self._get_cpu_state_handler = None 17 | self._continue_handler = None 18 | self._get_checksum_handler = None 19 | 20 | def set_read_handler(self, listener): 21 | self._read_handler = listener 22 | 23 | def set_write_handler(self, listener): 24 | self._write_handler = listener 25 | 26 | def set_set_cpu_state_handler(self, listener): 27 | self._set_cpu_state_handler= listener 28 | 29 | def set_get_cpu_state_handler(self, listener): 30 | self._get_cpu_state_handler= listener 31 | 32 | def set_continue_handler(self, listener): 33 | self._continue_handler= listener 34 | 35 | def set_get_checksum_handler(self, listener): 36 | self._get_checksum_handler= listener 37 | 38 | def _handle_read(self, params): 39 | assert(self._read_handler) #Read handler must be installed when this is called 40 | 41 | params["value"] = self._read_handler(params) 42 | 43 | return params["value"] 44 | 45 | def _handle_write(self, params): 46 | assert(self._write_handler) #Write handler must be installed when this is called 47 | 48 | self._write_handler(params) 49 | 50 | def _handle_set_cpu_state(self, params): 51 | assert(self._set_cpu_state_handler) 52 | 53 | self._set_cpu_state_handler(params) 54 | 55 | def _handle_get_cpu_state(self, params): 56 | assert(self._get_cpu_state_handler) 57 | 58 | return self._get_cpu_state_handler(params) 59 | 60 | def _handle_continue(self, params): 61 | assert(self._continue_handler) 62 | 63 | self._continue_handler(params) 64 | 65 | def _handle_get_checksum(self, params): 66 | assert(self._get_checksum_handler) 67 | 68 | return self._get_checksum_handler(params['address'], params['size']) 69 | 70 | class S2ERemoteMemoryInterface(RemoteMemoryInterface): 71 | def __init__(self, sock_address): 72 | super(S2ERemoteMemoryInterface, self).__init__() 73 | self._thread = threading.Thread(target = self._run) 74 | 75 | self._sock_address = sock_address 76 | self._stop = threading.Event() 77 | 78 | def start(self): 79 | self._thread.start() 80 | 81 | def _run(self): 82 | 83 | retries=1 84 | while retries < 10: 85 | try: 86 | log.debug("Connecting to S2E RemoteMemory plugin at %s:%d", self._sock_address[0], self._sock_address[1]) 87 | sock = socket.create_connection(self._sock_address) 88 | log.info("Connection to RemoteMemory plugin established") 89 | retries=10 90 | except Exception: 91 | log.exception("Connection to S2E RemoteMemory plugin failed (%d tries)" % retries) 92 | time.sleep(3) 93 | retries = retries+1 94 | sock=None 95 | 96 | #TODO: Do proper error signalling 97 | if not sock: 98 | sys.exit(1) 99 | 100 | while not self._stop.is_set(): 101 | buffer = "" 102 | while True: 103 | if self._stop.is_set(): 104 | return 105 | (rd, _, _) = select([sock], [], [], 1) 106 | if rd: 107 | buffer += sock.recv(1).decode(encoding = 'ascii') 108 | try: 109 | # this is outrageous 110 | request = json.loads(buffer) 111 | log.debug('buf: %s' % repr(buffer)) 112 | buffer = "" # reset the buffer if we were able to parse it 113 | request["cmd"] # wait for cmd? 114 | break 115 | except: 116 | # wait for more data 117 | pass 118 | try: 119 | if request["cmd"] == "read": 120 | params = {"address" : int(request["params"]["address"], 16), 121 | "size": int(request["params"]["size"], 16), 122 | "cpu_state": request["cpu_state"]} 123 | value = self._handle_read(params) 124 | json_string = json.dumps({"reply": "read", "value": "0x%x" % value}) + "\n" 125 | sock.send(json_string.encode(encoding = 'ascii')) 126 | elif request["cmd"] == "write": 127 | params = {"address" : int(request["params"]["address"], 16), 128 | "size": int(request["params"]["size"], 16), 129 | "value": int(request["params"]["value"], 16), 130 | "cpu_state": request["cpu_state"]} 131 | self._handle_write(params) 132 | elif request["cmd"] == "set_cpu_state": 133 | params = {"cpu_state": request["cpu_state"]} 134 | self._handle_set_cpu_state(params) 135 | json_string = json.dumps({"reply":"done"}) + \ 136 | "\n" 137 | sock.sendall(json_string.encode(encoding = 138 | 'ascii')) 139 | elif request["cmd"] == "get_cpu_state": 140 | params = None 141 | ret = self._handle_get_cpu_state(params) 142 | ret = dict(list(ret.items()) + list({"reply":"get_cpu_state"}.items())) 143 | json_string = json.dumps(ret) + "\n" 144 | sock.sendall(json_string.encode(encoding = 145 | 'ascii')) 146 | elif request["cmd"] == "continue": 147 | params = None 148 | self._handle_continue(params) 149 | # here we should wait for the breakpoint to be 150 | # hit 151 | json_string = json.dumps({"reply":"done"}) + \ 152 | "\n" 153 | sock.sendall(json_string.encode(encoding = 154 | 'ascii')) 155 | elif request["cmd"] == "write_buffer": 156 | params = {"address": int(request["address"], 16), 157 | "file": request["file"]} 158 | self._handle_write_buffer(params) 159 | elif request["cmd"] == "get_checksum": 160 | params = {"address": int(request["params"]["address"], 16), 161 | "size": int(request["params"]["size"], 16)} 162 | ret = self._handle_get_checksum(params) 163 | 164 | json_string = json.dumps({"reply":"done", \ 165 | "value": "0x%08x" % ret}) + \ 166 | "\n" 167 | sock.sendall(json_string.encode(encoding = 168 | 'ascii')) 169 | else: 170 | log.error("Unknown cmd %s" % (request['cmd'])) 171 | except Exception: 172 | log.exception("Error in remote memory interface") 173 | 174 | def stop(self): 175 | self._stop.set() 176 | 177 | -------------------------------------------------------------------------------- /avatar/plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avatarone/avatar-python/c6d74f85f63333e3031e1f5e208d3f90e316a9e4/avatar/plugins/__init__.py -------------------------------------------------------------------------------- /avatar/plugins/avatar_plugin.py: -------------------------------------------------------------------------------- 1 | class AvatarPlugin: 2 | """ 3 | Abstract interface for all Avatar plugins 4 | 5 | Upon start() and stop(), plugins are expected to register/unregister 6 | their own event handlers by the means of :func:`System.register_event_listener` 7 | and :func:`System.unregister_event_listener` 8 | """ 9 | 10 | def __init__(self, system): 11 | self._system = system 12 | 13 | def init(self, **kwargs): 14 | assert(False) #Not implemented 15 | 16 | def start(self, **kwargs): 17 | assert(False) #Not implemented 18 | 19 | def stop(self, **kwargs): 20 | assert(False) #Not implemented 21 | -------------------------------------------------------------------------------- /avatar/plugins/memory_range_identifier.py: -------------------------------------------------------------------------------- 1 | import json 2 | import logging 3 | from avatar.plugins.avatar_plugin import AvatarPlugin 4 | from avatar.system import EVENT_REQUEST_WRITE_MEMORY_VALUE,\ 5 | EVENT_REQUEST_READ_MEMORY_VALUE 6 | from functools import reduce 7 | 8 | 9 | log = logging.getLogger(__name__) 10 | 11 | class MemoryRangeIdentifier(AvatarPlugin): 12 | """ 13 | A plugin to identify memory regions, based on access type 14 | """ 15 | 16 | def __init__(self, system, page_size = 512): 17 | super().__init__(system) 18 | self._verbose = False 19 | self._page_size = page_size 20 | self._pages = {} 21 | 22 | def init(self, **kwargs): 23 | """ Setup the memory identifier """ 24 | if "verbose" in kwargs and kwargs["verbose"]: 25 | self._verbose = True 26 | pass 27 | 28 | def start(self, **kwargs): 29 | """ Start forwarded memory regions identification """ 30 | self._system.register_event_listener(self._process_event) 31 | pass 32 | 33 | def stop(self, **kwargs): 34 | """ Stop forwarded memory regions identification """ 35 | self._system.unregister_event_listener(self._process_event) 36 | pass 37 | 38 | def _get_page(self, address): 39 | pg_address = int(address / self._page_size) * self._page_size 40 | try: 41 | return self._pages[pg_address] 42 | except KeyError: 43 | self._pages[pg_address] = {"read": [0] * self._page_size, 44 | "write": [0] * self._page_size, 45 | "execute": [0] * self._page_size, 46 | "stack": [0] * self._page_size, 47 | "io": [0] * self._page_size, 48 | "data": [-1] * self._page_size} 49 | log.debug("Added page for address: 0x%x", pg_address) 50 | return self._pages[pg_address] 51 | 52 | def _write_data(self, address, size, value): 53 | assert(size == 1 or size == 2 or size == 4 or size == 8) 54 | assert(int(address / self._page_size) == int((address + size - 1) / self._page_size)) 55 | 56 | page = self._get_page(address) 57 | offset = address % self._page_size 58 | for i in range(0, size): 59 | page["data"][offset + i] = (value >> (8 * i)) & 0xFF 60 | 61 | def _read_cached_data(self, address, size): 62 | assert(size == 1 or size == 2 or size == 4 or size == 8) 63 | assert(int(address / self._page_size) == int((address + size - 1) / self._page_size)) 64 | 65 | page = self._get_page(address) 66 | offset = address % self._page_size 67 | value = 0 68 | #TODO: Only works for little endian 69 | for i in range(0, size): 70 | if page["data"][offset + i] < 0: 71 | #Memory has not yet been written to 72 | return None 73 | value = value | (page["data"][offset + i] << (8 * i)) 74 | 75 | return value 76 | 77 | def _mark_data(self, address, size, mark): 78 | assert(size == 1 or size == 2 or size == 4 or size == 8) 79 | assert(int(address / self._page_size) == int((address + size - 1) / self._page_size)) 80 | assert(mark in ["read", "write", "execute", "stack", "io"]) 81 | 82 | page = self._get_page(address) 83 | offset = address % self._page_size 84 | for i in range(offset, offset + size): 85 | page[mark][i] += 1 86 | 87 | def _mark_data_read(self, address, size): 88 | self._mark_data(address, size, "read") 89 | 90 | def _mark_data_write(self, address, size): 91 | self._mark_data(address, size, "write") 92 | 93 | def _mark_data_execute(self, address, size): 94 | self._mark_data(address, size, "execute") 95 | 96 | def _mark_data_stack(self, address, size): 97 | self._mark_data(address, size, "stack") 98 | 99 | def _mark_data_io(self, address, size): 100 | self._mark_data(address, size, "io") 101 | 102 | def _add_stack_pointer_value(self, sp, cpsr): 103 | if self._verbose: 104 | log.info({"type": "sp", "sp": sp, "cpsr": cpsr}) 105 | self._mark_data_stack(sp, 4) 106 | 107 | def _add_program_counter_value(self, pc, cpsr): 108 | if self._verbose: 109 | log.info({"type": "pc", "pc": pc, "cpsr": cpsr}) 110 | if cpsr & (1 << 5): 111 | self._mark_data_execute(pc, 2) 112 | else: 113 | self._mark_data_execute(pc, 4) 114 | 115 | def _add_memory_read_access(self, cpsr, address, size, value=None): 116 | if self._verbose: 117 | evt = {"type": "read", "address": address, "size": size, "cpsr": cpsr} 118 | log.info(json.dumps(evt) + "\n") 119 | self._mark_data_read(address, size) 120 | if value: 121 | stored_value = self._read_cached_data(address, size) 122 | if (not stored_value is None) and stored_value != value: 123 | log.debug("stored_value = 0x%08x, value = 0x%08x" % (stored_value, value)) 124 | self._mark_data_io(address, size) 125 | self._write_data(address, size, value) 126 | 127 | 128 | def _add_memory_write_access(self, cpsr, address, size, value): 129 | if self._verbose: 130 | evt = {"type": "write", "address": address, "size": size, "value": value, "cpsr": cpsr} 131 | log.info(json.dumps(evt) + "\n") 132 | self._mark_data_write(address, size) 133 | self._write_data(address, size, value) 134 | 135 | def _get_pageinfo(self, path): 136 | pageinfo = [] 137 | for (pg_address, page) in sorted(self._pages.items(), key = operator.itemgetter(0)): 138 | pageinfo.append({"address": pg_address, 139 | "read": sum(page["read"]), 140 | "write": sum(page["write"]), 141 | "execute": sum(page["execute"]), 142 | "stack": sum(page["stack"]), 143 | "io": sum(page["io"])}) 144 | 145 | return pageinfo 146 | 147 | def _process_event(self, evt): 148 | if evt["source"] == "emulator": 149 | memory_access = False 150 | if EVENT_REQUEST_WRITE_MEMORY_VALUE in evt["tags"]: 151 | memory_access = True 152 | self._add_memory_write_access(int(evt["properties"]["cpu_state"]["cpsr"], 16), 153 | evt["properties"]["address"], 154 | evt["properties"]["size"], 155 | evt["properties"]["value"], 156 | ) 157 | elif EVENT_REQUEST_READ_MEMORY_VALUE in evt["tags"]: 158 | self._add_memory_read_access(int(evt["properties"]["cpu_state"]["cpsr"], 16), 159 | evt["properties"]["address"], 160 | evt["properties"]["size"], 161 | ) 162 | memory_access = True 163 | if (memory_access): 164 | self._add_stack_pointer_value(int(evt["properties"]["cpu_state"]["r13"], 16), 165 | int(evt["properties"]["cpu_state"]["cpsr"], 16)) 166 | self._add_program_counter_value(int(evt["properties"]["cpu_state"]["pc"], 16), 167 | int(evt["properties"]["cpu_state"]["cpsr"], 16)) 168 | 169 | -------------------------------------------------------------------------------- /avatar/system.py: -------------------------------------------------------------------------------- 1 | #from configuration.manager import ConfigurationManager 2 | #from interfaces.s2e_remote_memory import S2ERemoteMemoryInterface 3 | #from interfaces.avatar_protocol import AvatarProtocol 4 | #from util.socket_file import SocketFile 5 | #from exceptions import OSError 6 | #import signal 7 | #import subprocess 8 | #import os 9 | #import atexit 10 | #import sys 11 | #import socket 12 | #import threading 13 | #import logging 14 | 15 | from threading import Event, Thread 16 | import logging 17 | import sys 18 | import os 19 | from avatar.util.ostools import mkdir_p 20 | from avatar.call_proxy import EmulatorTargetCallProxy 21 | from queue import Empty, Queue 22 | 23 | 24 | 25 | CONSOLE_LOG_FORMAT = "%(levelname)s - %(message)s" 26 | FILE_LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s' 27 | #log = logging.getLogger(__module__ + "." + __name__) 28 | log = logging.getLogger(__name__) 29 | 30 | #Event tags 31 | EVENT_STOPPED = "EVENT_STOPPED" 32 | EVENT_BREAKPOINT = "EVENT_BREAKPOINT" 33 | EVENT_END_STEPPING = "EVENT_END_STEPPING" 34 | EVENT_RUNNING = "EVENT_RUNNING" 35 | EVENT_REQUEST_READ_MEMORY_VALUE = "EVENT_REQUEST_READ_MEMORY_VALUE" 36 | EVENT_REQUEST_WRITE_MEMORY_VALUE = "EVENT_REQUEST_WRITE_MEMORY_VALUE" 37 | EVENT_RESPONSE_READ_MEMORY_VALUE = "EVENT_RESPONSE_READ_MEMORY_VALUE" 38 | EVENT_RESPONSE_WRITE_MEMORY_VALUE = "EVENT_RESPONSE_WRITE_MEMORY_VALUE" 39 | EVENT_SIGABRT = "EVENT_SIGABRT" 40 | 41 | class EventWaiter(): 42 | def __init__(self, system): 43 | self._queue = Queue() 44 | self._system = system 45 | system.register_event_listener(self._queue_event) 46 | 47 | def _queue_event(self, evt): 48 | self._queue.put(evt) 49 | 50 | def wait_event(self): 51 | return self._queue.get() 52 | 53 | def __del__(self): 54 | self._system.unregister_event_listener(self._queue_event) 55 | 56 | class System(): 57 | def __init__(self, configuration, create_emulator, create_target): 58 | self._configuration = configuration 59 | self._plugins = [] 60 | self._terminating = Event() 61 | self._call_proxy = EmulatorTargetCallProxy() 62 | self._emulator = None 63 | self._target = None 64 | self._listeners = [] 65 | self._events = Queue() 66 | 67 | 68 | #Setup logging to console 69 | # logging.basicConfig(level = logging.DEBUG, format = CONSOLE_LOG_FORMAT) 70 | # console_log_handler = logging.StreamHandler() 71 | # console_log_handler.setLevel(logging.DEBUG) 72 | # console_log_handler.setFormatter(logging.Formatter(CONSOLE_LOG_FORMAT)) 73 | # logging.getLogger("").addHandler(console_log_handler) 74 | # logging.getLogger("").setLevel(logging.DEBUG) 75 | 76 | #Check if output directory exists, and create it if not 77 | output_directory = configuration["output_directory"] 78 | if os.path.exists(output_directory) and not os.path.isdir(output_directory): 79 | log.error("Output destination exists, but is not a directory") 80 | sys.exit(1) 81 | 82 | if not os.path.exists(output_directory): 83 | log.info("Output directory did not exist, trying to create it") 84 | mkdir_p(output_directory) 85 | 86 | if os.listdir(output_directory): 87 | log.warn("Output directory is not empty, will overwrite files") 88 | 89 | #Now the output directory should exist, divert a logging stream there 90 | file_log_handler = logging.FileHandler(filename = os.path.join(output_directory, "avatar.log"), mode = 'w') 91 | file_log_handler.setLevel(logging.DEBUG) 92 | file_log_handler.setFormatter(logging.Formatter(FILE_LOG_FORMAT)) 93 | logging.getLogger("").addHandler(file_log_handler) 94 | # console_log_handler.setLevel(logging.INFO) 95 | 96 | self._event_thread = Thread(target = self._process_events) 97 | self._event_thread.start() 98 | 99 | create_emulator(self) 100 | create_target(self) 101 | 102 | 103 | def get_configuration(self): 104 | return self._configuration 105 | 106 | def init(self): 107 | self._emulator.init() 108 | self._target.init() 109 | 110 | def start(self): 111 | assert(self._emulator) #Start emulator hook needs to be set! 112 | assert(self._target) #Start target hook needs to be set! 113 | 114 | self._emulator.set_read_request_handler(self._call_proxy.handle_emulator_read_request) 115 | self._emulator.set_write_request_handler(self._call_proxy.handle_emulator_write_request) 116 | self._emulator.set_set_cpu_state_request_handler(self._call_proxy.handle_emulator_set_cpu_state_request) 117 | self._emulator.set_get_cpu_state_request_handler(self._call_proxy.handle_emulator_get_cpu_state_request) 118 | self._emulator.set_continue_request_handler(self._call_proxy.handle_emulator_continue_request) 119 | self._emulator.set_get_checksum_request_handler(self._call_proxy.handle_emulator_get_checksum_request) 120 | self._call_proxy.set_target(self._target) 121 | 122 | self._target.start() 123 | self._emulator.start() 124 | 125 | 126 | def stop(self): 127 | if not self._terminating.is_set(): 128 | self._terminating.set() 129 | self._emulator.stop() 130 | self._target.stop() 131 | self._call_proxy.stop_monitors() 132 | 133 | def set_emulator(self, emulator): 134 | """This method is supposed to be called by the emulator init function 135 | when it sets the actual emulator object. The _emulator variable should 136 | not be set directly, as some decoration might happen.""" 137 | self._emulator = emulator 138 | 139 | def set_target(self, target): 140 | """This method is supposed to be called by the target init function 141 | when it sets the actual target object. The _target variable should 142 | not be set directly, as some decoration might happen.""" 143 | self._target = target 144 | 145 | def get_emulator(self): 146 | return self._emulator 147 | 148 | def get_target(self): 149 | return self._target 150 | 151 | def add_monitor(self, monitor): 152 | self._call_proxy.add_monitor(monitor) 153 | 154 | def post_event(self, evt): 155 | if not "properties" in evt: 156 | evt["properties"] = {} 157 | self._events.put(evt) 158 | 159 | def register_event_listener(self, listener): 160 | self._listeners.append(listener) 161 | 162 | def unregister_event_listener(self, listener): 163 | self._listeners.remove(listener) 164 | 165 | def _process_events(self): 166 | while not self._terminating.is_set(): 167 | try: 168 | evt = self._events.get(1) 169 | log.debug("Processing event: '%s'", str(evt)) 170 | for listener in self._listeners: 171 | try: 172 | listener(evt) 173 | except Exception: 174 | log.exception("Exception while handling event") 175 | except Empty: 176 | pass 177 | except Exception as ex: 178 | log.exception("Some more serious exception handled while processing events. Investigate.") 179 | raise ex 180 | 181 | 182 | -------------------------------------------------------------------------------- /avatar/targets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avatarone/avatar-python/c6d74f85f63333e3031e1f5e208d3f90e316a9e4/avatar/targets/__init__.py -------------------------------------------------------------------------------- /avatar/targets/avatarstub_target.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Jun 24, 2013 3 | 4 | @author: Jonas Zaddach 5 | ''' 6 | from avatar.targets.target import Target 7 | import socket 8 | import logging 9 | from avatar.interfaces.avatar_stub.avatar_protocol import AvatarProtocol 10 | from avatar.system import EVENT_STOPPED, EVENT_BREAKPOINT 11 | from avatar.debuggable import Breakpoint 12 | from queue import Queue 13 | 14 | log = logging.getLogger(__name__) 15 | 16 | ARM_REGISTER_NAMES = {"r0": 0, 17 | "r1": 1, 18 | "r2": 2, 19 | "r3": 3, 20 | "r4": 4, 21 | "r5": 5, 22 | "r6": 6, 23 | "r7": 7, 24 | "r8": 8, 25 | "r9": 9, 26 | "r10": 10, 27 | "r11": 11, 28 | "r12": 12, 29 | "r13": 13, 30 | "sp": 13, 31 | "r14": 14, 32 | "lr": 14, 33 | "r15": 15, 34 | "pc": 15, 35 | "cpsr": 16} 36 | 37 | class AvatarBreakpoint(Breakpoint): 38 | def __init__(self, system, address): 39 | super().__init__() 40 | self._system = system 41 | self._address = address 42 | self._queue = Queue() 43 | system.register_event_listener(self._event_receiver) 44 | 45 | def wait(self, timeout = None): 46 | if self._handler: 47 | raise Exception("Breakpoint cannot have a handler and be waited on") 48 | 49 | if timeout == 0: 50 | return self._queue.get(False) 51 | else: 52 | return self._queue.get(True, timeout) 53 | 54 | def delete(self): 55 | self._system.unregister_event_listener(self._event_receiver) 56 | self._system.get_target().clear_breakpoint(self._address) 57 | 58 | def _event_receiver(self, evt): 59 | if EVENT_BREAKPOINT in evt["tags"] and \ 60 | evt["source"] == "target" and \ 61 | evt["properties"]["address"] == self._address: 62 | if self._handler: 63 | self._handler(self._system, self) 64 | else: 65 | self._queue.put(evt) 66 | 67 | class AvatarstubTarget(Target): 68 | def __init__(self, system): 69 | self._system = system 70 | self._breakpoints = {} 71 | 72 | def init(self): 73 | conf = self._system.get_configuration() 74 | assert("avatar_configuration" in conf) 75 | assert("target_gdb_address" in conf["avatar_configuration"]) 76 | assert(conf["avatar_configuration"]["target_gdb_address"].startswith("tcp:")) 77 | sockaddr_str = conf["avatar_configuration"]["target_gdb_address"][4:] 78 | sockaddr = (sockaddr_str[:sockaddr_str.rfind(":")], 79 | int(sockaddr_str[sockaddr_str.rfind(":") + 1:])) 80 | self._sockaddress = sockaddr 81 | 82 | def start(self): 83 | #TODO: Handle timeout 84 | log.info("Trying to connect to target avatar server at %s:%d", self._sockaddress[0], self._sockaddress[1]) 85 | self._socket = socket.create_connection(self._sockaddress, 10) 86 | self._avatar_connection = AvatarProtocol(self._socket, self._handle_asynchronous_message) 87 | 88 | def read_typed_memory(self, address, size): 89 | return self._avatar_connection.read_memory(address, size) 90 | 91 | def read_untyped_memory(self, address, length): 92 | return self._avatar_connection.read_memory_untyped(address, length) 93 | 94 | def write_typed_memory(self, address, size, value): 95 | self._avatar_connection.write_memory(address, size, value) 96 | 97 | def write_untyped_memory(self, address, data): 98 | chunk_address = address 99 | remaining_size = len(data) 100 | while remaining_size > 0: 101 | self._avatar_connection.write_memory_untyped(address, data[address:address + 255]) 102 | chunk_address += 255 103 | remaining_size -= 255 104 | 105 | def get_register(self, name): 106 | if isinstance(name, str): 107 | name = ARM_REGISTER_NAMES[name.lower()] 108 | return self._avatar_connection.get_register(name) 109 | 110 | def set_register(self, name, value): 111 | if isinstance(name, str): 112 | name = ARM_REGISTER_NAMES[name.lower()] 113 | self._avatar_connection.set_register(name, value) 114 | 115 | def install_codelet(self, address, codelet): 116 | self.write_untyped_memory(address, codelet) 117 | 118 | def execute_codelet(self, address): 119 | self._avatar_connection.execute_codelet(address) 120 | 121 | def set_breakpoint(self, address, **properties): 122 | if address in self._breakpoints: 123 | raise Exception("Breakpoint at 0x%x already set, not setting a new one" % address) 124 | 125 | bkpt = {"instruction_set": "arm"} 126 | if "thumb" in properties and properties['thumb']: 127 | bkpt["instruction_set"] = "thumb" 128 | 129 | self._breakpoints[address] = bkpt 130 | 131 | return AvatarBreakpoint(self._system, address) 132 | 133 | def clear_breakpoint(self, address): 134 | del self._breakpoints[address] 135 | 136 | def cont(self): 137 | pc = self.get_register("pc") 138 | for (bkpt_address, bkpt_data) in self._breakpoints.items(): 139 | if bkpt_address == pc: 140 | continue 141 | 142 | if bkpt_data["instruction_set"] == "arm": 143 | self.write_typed_memory(bkpt_address, 4, 0xe1200071) 144 | elif bkpt_data["instruction_set"] == "thumb": 145 | self.write_typed_memory(bkpt_address, 2, 0xbe01) 146 | self._avatar_connection.cont() 147 | 148 | def _handle_asynchronous_message(self, msg): 149 | print("Received event") 150 | if msg.name == "AVATAR_RPC_DTH_STATE": 151 | #TODO: Look at state and act accordingly (Breakpoint, page fault, etc) 152 | self._system.post_event({"tags": [EVENT_STOPPED, EVENT_BREAKPOINT], 153 | "channel": "avatar", 154 | "source": "target", 155 | "properties": { 156 | "address": self.get_register("pc")}}) 157 | 158 | 159 | 160 | 161 | def init_avatarstub_target(system): 162 | system.set_target(AvatarstubTarget(system)) 163 | 164 | -------------------------------------------------------------------------------- /avatar/targets/gdbserver_target.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Jun 24, 2013 3 | 4 | @author: Jonas Zaddach 5 | ''' 6 | from avatar.targets.target import Target 7 | import logging 8 | from avatar.bintools.gdb.gdb_debugger import GdbDebugger 9 | from avatar.system import EVENT_RUNNING, EVENT_STOPPED, EVENT_BREAKPOINT, EVENT_SIGABRT 10 | from avatar.bintools.gdb.mi_parser import Async 11 | from avatar.debuggable import Breakpoint 12 | from queue import Queue 13 | 14 | log = logging.getLogger(__name__) 15 | 16 | class GdbBreakpoint(Breakpoint): 17 | def __init__(self, system, bkpt_num, address): 18 | super().__init__() 19 | self._system = system 20 | self._bkpt_num = bkpt_num 21 | self._queue = Queue() 22 | self.address = address 23 | system.register_event_listener(self._event_receiver) 24 | 25 | def wait(self, timeout = None): 26 | if self._handler: 27 | raise Exception("Breakpoint cannot have a handler and be waited on") 28 | 29 | if timeout == 0: 30 | return self._queue.get(False) 31 | else: 32 | return self._queue.get(True, timeout) 33 | 34 | def delete(self): 35 | self._system.unregister_event_listener(self._event_receiver) 36 | self._system.get_target()._gdb_interface.delete_breakpoint(self._bkpt_num) 37 | 38 | def _event_receiver(self, evt): 39 | if EVENT_BREAKPOINT in evt["tags"] and \ 40 | evt["source"] == "target" and \ 41 | evt["properties"]["bkpt_number"] == self._bkpt_num: 42 | if self._handler: 43 | self._handler(self._system, self) 44 | else: 45 | self._queue.put(evt) 46 | elif EVENT_SIGABRT in evt["tags"]: 47 | self._queue.put(evt) 48 | 49 | class GdbserverTarget(Target): 50 | def __init__(self, system, verbose=False): 51 | self._system = system 52 | self._verbose = verbose 53 | 54 | def init(self): 55 | conf = self._system.get_configuration() 56 | assert("avatar_configuration" in conf) 57 | assert("target_gdb_address" in conf["avatar_configuration"]) 58 | assert(conf["avatar_configuration"]["target_gdb_address"].startswith("tcp:")) 59 | sockaddr_str = conf["avatar_configuration"]["target_gdb_address"][4:] 60 | if "target_gdb_path" in conf["avatar_configuration"]: 61 | self.gdb_exec= conf["avatar_configuration"]["target_gdb_path"] 62 | else: 63 | self.gdb_exec = "/home/zaddach/projects/hdd-svn/gdb/gdb/gdb" 64 | log.warn("target_gdb_path not defined in avatar configuration, using hardcoded GDB path: %s", self.gdb_exec) 65 | if "target_gdb_additional_arguments" in conf["avatar_configuration"]: 66 | self.additional_args = conf["avatar_configuration"]["target_gdb_additional_arguments"] 67 | else: 68 | self.additional_args = [] 69 | self._sockaddress = (sockaddr_str[:sockaddr_str.rfind(":")], 70 | int(sockaddr_str[sockaddr_str.rfind(":") + 1:])) 71 | 72 | def start(self): 73 | #TODO: Handle timeout 74 | if self._verbose: log.info("Trying to connect to target gdb server at %s:%d", self._sockaddress[0], self._sockaddress[1]) 75 | self._gdb_interface = GdbDebugger(gdb_executable = self.gdb_exec, cwd = ".", additional_args = self.additional_args ) 76 | self._gdb_interface.set_async_message_handler(self.handle_gdb_async_message) 77 | self._gdb_interface.connect(("tcp", self._sockaddress[0], "%d" % self._sockaddress[1])) 78 | 79 | def write_typed_memory(self, address, size, data): 80 | self._gdb_interface.write_memory(address, size, data) 81 | 82 | def read_typed_memory(self, address, size): 83 | return self._gdb_interface.read_memory(address, size) 84 | 85 | def set_register(self, reg, val): 86 | self._gdb_interface.set_register(reg, val) 87 | 88 | def get_register(self, reg): 89 | return self._gdb_interface.get_register(reg) 90 | 91 | def get_register_from_nr(self, num): 92 | try: 93 | return self.get_register(["r0", "r1", "r2", "r3", "r4", "r5", 94 | "r6", "r7", "r8", "r9", "r10", 95 | "r11", "r12", "sp", "lr", "pc", "cpsr"][num]) 96 | except IndexError: 97 | log.warn("get_register_from_nr called with unexpected register index %d", num) 98 | return 0 99 | 100 | def execute_gdb_command(self, cmd): 101 | return self._gdb_interface.execute_gdb_command(cmd) 102 | def get_checksum(self, addr, size): 103 | return self._gdb_interface.get_checksum(addr, size) 104 | 105 | def stop(self): 106 | pass 107 | 108 | def set_breakpoint(self, address, **properties): 109 | if "thumb" in properties: 110 | del properties["thumb"] 111 | bkpt = self._gdb_interface.insert_breakpoint(address, *properties) 112 | return GdbBreakpoint(self._system, int(bkpt["bkpt"]["number"]), address) 113 | 114 | 115 | def cont(self): 116 | self._gdb_interface.cont() 117 | 118 | def handle_gdb_async_message(self, msg): 119 | print("Received async message: '%s'" % str(msg)) 120 | if msg.type == Async.EXEC: 121 | if msg.klass == "running": 122 | self._post_event({"tags": [EVENT_RUNNING], "channel": "gdb"}) 123 | elif msg.klass == "stopped": 124 | if "reason" in msg.results and msg.results["reason"] == "breakpoint-hit": 125 | self._post_event({"tags": [EVENT_STOPPED, EVENT_BREAKPOINT], 126 | "properties": { 127 | "address": int(msg.results["frame"]["addr"], 16), 128 | "bkpt_number": int(msg.results["bkptno"])}, 129 | "channel": "gdb"}) 130 | elif "reason" in msg.results and msg.results["reason"] == "signal-received": 131 | # this is data abort 132 | try: 133 | addr = int(msg.results["frame"]["addr"], 16) 134 | except: 135 | addr = 0xDEADDEAD 136 | self._post_event({"tags": [EVENT_STOPPED, EVENT_SIGABRT], 137 | "properties": { 138 | "address": addr, 139 | }, 140 | "channel": "gdb"}) 141 | def _post_event(self, evt): 142 | evt["source"] = "target" 143 | self._system.post_event(evt) 144 | 145 | 146 | @classmethod 147 | def from_str(cls, sockaddr_str): 148 | assert(sockaddr_str.startswith("tcp:")) 149 | sockaddr = (sockaddr_str[:sockaddr_str.rfind(":")], 150 | int(sockaddr_str[sockaddr_str.rfind(":") + 1:])) 151 | return cls(sockaddr) 152 | 153 | def init_gdbserver_target(system): 154 | system.set_target(GdbserverTarget(system)) 155 | 156 | -------------------------------------------------------------------------------- /avatar/targets/jig.py: -------------------------------------------------------------------------------- 1 | class Jig(): 2 | """This is an interface for all objects that acts as hardware jig (ie. gdb monitors)""" 3 | def attach(self): 4 | """Attach to target board""" 5 | assert(False) #No implementation 6 | 7 | def detach(self, address, size, value): 8 | """Detach from target board""" 9 | assert(False) #No implementation 10 | 11 | def get_gdb_jigstr(self): 12 | """Return a socket endpoint string for a Gdbserver""" 13 | assert(False) #No implementation 14 | 15 | def get_gdb_jigosck(self): 16 | """Return a socket endpoint string for a Gdbserver""" 17 | assert(False) #No implementation 18 | 19 | def get_telnet_jigstr(self): 20 | """Return a socket endpoint string for a Gdbserver""" 21 | assert(False) #No implementation 22 | 23 | def get_telnet_jigosck(self): 24 | """Return a socket endpoint string for a Gdbserver""" 25 | assert(False) #No implementation 26 | -------------------------------------------------------------------------------- /avatar/targets/null_target.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Jun 24, 2013 3 | 4 | @author: Jonas Zaddach 5 | ''' 6 | from avatar.targets.target import Target 7 | import logging 8 | from avatar.bintools.gdb.gdb_debugger import GdbDebugger 9 | from avatar.system import EVENT_RUNNING, EVENT_STOPPED, EVENT_BREAKPOINT 10 | from avatar.bintools.gdb.mi_parser import Async 11 | from avatar.debuggable import Breakpoint 12 | from queue import Queue 13 | 14 | log = logging.getLogger(__name__) 15 | 16 | class NullTarget(Target): 17 | def __init__(self, system, verbose=False): 18 | pass 19 | 20 | def init(self): 21 | pass 22 | 23 | def start(self): 24 | pass 25 | 26 | def write_typed_memory(self, address, size, data): 27 | pass 28 | 29 | def read_typed_memory(self, address, size): 30 | pass 31 | 32 | def set_register(self, reg, val): 33 | pass 34 | 35 | def get_register(self, reg): 36 | pass 37 | 38 | def stop(self): 39 | pass 40 | 41 | def set_breakpoint(self, address, **properties): 42 | pass 43 | 44 | 45 | def cont(self): 46 | pass 47 | 48 | def init_null_target(system): 49 | system.set_target(NullTarget(system)) -------------------------------------------------------------------------------- /avatar/targets/openocd_jig.py: -------------------------------------------------------------------------------- 1 | ''' 2 | @author: Luca BRUNO 3 | ''' 4 | from avatar.targets.jig import Jig 5 | import socket 6 | import logging 7 | import subprocess 8 | import time 9 | import os 10 | 11 | log = logging.getLogger(__name__) 12 | 13 | class OpenocdJig(Jig): 14 | def __init__(self, cfg): 15 | assert "openocd_configuration" in cfg 16 | assert "config_file" in cfg["openocd_configuration"] 17 | self._fname = cfg["openocd_configuration"]["config_file"] 18 | if self._fname[0] != '/': 19 | self._fname = cfg["configuration_directory"] + '/' + self._fname 20 | self._gdbaddress = ("127.0.0.1", 3333) 21 | self._telnetaddress = ("127.0.0.1", 4444) 22 | self.attach() 23 | 24 | def attach(self): 25 | with open(os.devnull, "w") as fnull: 26 | self._pid = subprocess.Popen(["openocd", "-f", self._fname], stdout=fnull) 27 | time.sleep(1) #Openocd initialization takes some time 28 | 29 | def detach(self): 30 | self._pid.kill() 31 | 32 | def get_gdb_jigstr(self): 33 | return "tcp:"+':'.join(str(i) for i in self._gdbaddress) 34 | 35 | def get_gdb_jigsock(self): 36 | return self._gdbaddress 37 | 38 | def get_telnet_jigstr(self): 39 | return "tcp:"+':'.join(str(i) for i in self._telnetaddress) 40 | 41 | def get_telnet_jigsock(self): 42 | return self._telnetaddress 43 | 44 | def __del__(self): 45 | self.detach() 46 | 47 | @classmethod 48 | def from_cfg(cls, cfg): 49 | return cls(cfg) 50 | 51 | @classmethod 52 | def from_str(cls, exe): 53 | cfg=[] 54 | cfg["openocd_configuration"]["config_file"] = exe 55 | return cls(cfg) 56 | 57 | -------------------------------------------------------------------------------- /avatar/targets/openocd_target.py: -------------------------------------------------------------------------------- 1 | from avatar.targets.target import Target 2 | import socket 3 | import logging 4 | import telnetlib 5 | 6 | log = logging.getLogger(__name__) 7 | 8 | #This names are OpenOCD specific 9 | ARM_REGISTERS = ["r0", "r1","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11", 10 | "r12","sp_usr","lr_usr","pc","cpsr","r8_fiq","r9_fiq", 11 | "r10_fiq","r11_fiq","r12_fiq","sp_fiq","lr_fiq","spsr_fiq", 12 | "sp_svc","lr_svc","spsr_svc","sp_abt","lr_abt","spsr_abt", 13 | "sp_irq","lr_irq","spsr_irq","sp_und","lr_und","spsr_und"] 14 | 15 | # Decorator for methods requiring target Stop&Start 16 | def paused(fn): 17 | # TODO: variadic decorator 18 | def wrapped(self, opt=None): 19 | self.halt() 20 | if opt: 21 | fn(self, opt) 22 | else: 23 | fn(self) 24 | self.cont() 25 | return wrapped 26 | 27 | # Decorator for methods requiring target Hard Stop 28 | def halted(fn): 29 | # TODO: variadic decorator 30 | def wrapped(self, opt=None): 31 | self.halt() 32 | if opt: 33 | return fn(self, opt) 34 | else: 35 | return fn(self) 36 | return wrapped 37 | 38 | 39 | class OpenocdTarget(Target): 40 | """ 41 | This module includes the logic to talk with OpenOCD in order to 42 | perform low-level actions on the target. 43 | Methods are split in three classes, according to their decorator: 44 | * paused: stop the target before performing actions, then resume it 45 | * halted: stop the target to perform actions 46 | * raw: plain naked actions 47 | """ 48 | 49 | def __init__(self, sockaddr): 50 | self._sockaddress = sockaddr 51 | self._prompt = telnetlib.Telnet() 52 | self.start() 53 | 54 | ################################################################### 55 | ## Raw naked methods 56 | ################################################################### 57 | 58 | def start(self): 59 | """ Start the telnet session to OpenOCD """ 60 | log.info("Trying to connect to target openocd server at %s:%d", self._sockaddress[0], self._sockaddress[1]) 61 | self._prompt.open(self._sockaddress[0], self._sockaddress[1]) 62 | self.get_output() 63 | 64 | def stop(self): 65 | """ Stop the telnet session to OpenOCD """ 66 | self.send_cmd("exit") 67 | self._prompt.close() 68 | del self._prompt 69 | 70 | def wait(self): 71 | self.get_output() 72 | 73 | def get_output(self, to=0): 74 | """ 75 | Get the output of last command 76 | :param to: timeout in seconds (optional) 77 | :type to: int 78 | """ 79 | if to == 0: 80 | out = str(self._prompt.read_until(b"> ")) 81 | else: 82 | out = str(self._prompt.read_until(b"> ", to)) 83 | out = out.split("> ")[0] 84 | return out 85 | 86 | def halt(self): 87 | """ Stop the target """ 88 | self.raw_cmd("halt", False) 89 | 90 | def cont(self): 91 | """ Resume the target """ 92 | self.raw_cmd("resume", False) 93 | 94 | def raw_cmd(self, cmd, is_log=True): 95 | """ 96 | Send a raw command to OpenOCD 97 | :param cmd: an OpenOCD command 98 | :type cmd: str 99 | :param is_log: whether to log command output (optional, default True) 100 | :type is_log: bool 101 | """ 102 | self._prompt.write(str(cmd+'\n').encode("ascii")) 103 | out=self.get_output() 104 | if is_log: 105 | log.info(out) 106 | return out 107 | 108 | def put_raw_bp(self, addr : "str 0xNNNNNNNN", size : "int"): 109 | """ 110 | Put a breakpoint 111 | :param addr: address literal in hexadecimal 112 | :type addr: str 113 | :param size: brakpoint size 114 | :type size: integer 115 | """ 116 | # FIXME: hardcoded hw breakpoint 117 | self.raw_cmd("bp %s %d hw" % (addr, size)) 118 | 119 | def remove_raw_bp(self, addr : "str 0xNNNNNNNN"): 120 | """ 121 | Remove a breakpoint 122 | :param addr: address literal in hexadecimal 123 | :type addr: str 124 | """ 125 | self.raw_cmd("rbp %s" % addr) 126 | 127 | def get_raw_register(self, regname : "str")-> "str 0xNNNNNNNN": 128 | """ 129 | Read a single register, allowed values within ARM_REGISTERS 130 | :param regname: register name (see ARM_REGISTERS) 131 | :type regname: str 132 | :return: value register in hexadecimal 133 | :rtype: str 134 | """ 135 | assert(regname in ARM_REGISTERS) 136 | value=self.raw_cmd("reg " + regname, False).split(": ")[-1] 137 | # XXX 138 | return value.split("\\")[0] 139 | 140 | def initstate(self, cfg : "dict of str"): 141 | """ Change S2E configurable machine initial setup""" 142 | assert("machine_configuration" in cfg) 143 | self.get_output(2) 144 | st = self.dump_all_registers() 145 | cfg["machine_configuration"]["init_state"] = [st] 146 | # Override entry address 147 | if "pc" in st: 148 | cfg["machine_configuration"]["entry_address"] = st["pc"] 149 | return cfg 150 | 151 | ################################################################### 152 | ## Paused methods 153 | ################################################################### 154 | 155 | @paused 156 | def put_bp(self, addr : "str 0xNNNNNNNN"): 157 | """ 158 | Pause the target, put a breakpoint, then resume it 159 | :param addr: address literal in hexadecimal 160 | :type addr: str 161 | """ 162 | # XXX: hardcoded: thumb, hw breakpoint 163 | self.raw_cmd("bp %s 2 hw" % addr) 164 | 165 | @paused 166 | def remove_bp(self, addr : "str 0xNNNNNNNN"): 167 | """ 168 | Pause the target, remove a breakpoint, the resume it 169 | :param addr: address literal in hexadecimal 170 | :type addr: str 171 | """ 172 | self.remove_raw_bp(addr) 173 | 174 | @paused 175 | def get_register(self, regname : "str") -> "str 0xNNNNNNNN": 176 | """ 177 | Pause the target, read a single register, then resume it 178 | :param regname: register name (allowed values within ARM_REGISTERS) 179 | :type regname: str 180 | :return: value register in hexadecimal 181 | :rtype: str 182 | """ 183 | return self.get_raw_register(regname) 184 | 185 | ################################################################### 186 | ## Halted methods 187 | ################################################################### 188 | 189 | @halted 190 | def dump_all_registers(self)-> "dict{str: str 0xNNNNNNNN}": 191 | """ 192 | Halt the target, loop over all available registers 193 | and dump their content 194 | :return: dict of regname->value 195 | :rtype: dict of str->str 196 | """ 197 | out = {} 198 | # Flush session input 199 | self.get_output(2) 200 | for i in ARM_REGISTERS: 201 | val = self.get_raw_register(i) 202 | try: 203 | out[i] = int(val, 0) # thanks json 204 | except Exception as ex: 205 | log.exception("%s ignored, read value was «%s»" % (i, val)) 206 | return out 207 | 208 | ################################################################### 209 | ## Class methods 210 | ################################################################### 211 | 212 | @classmethod 213 | def from_str(cls, sockaddr_str: "str, proto:addr:port"): 214 | """ Static factory """ 215 | assert(sockaddr_str.startswith("tcp:")) 216 | sockaddr = (sockaddr_str[:sockaddr_str.rfind(":")], 217 | int(sockaddr_str[sockaddr_str.rfind(":") + 1:])) 218 | return cls(sockaddr) 219 | 220 | -------------------------------------------------------------------------------- /avatar/targets/target.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Jun 24, 2013 3 | 4 | @author: Jonas Zaddach 5 | ''' 6 | from avatar.debuggable import Debuggable 7 | 8 | class Target(Debuggable): 9 | pass -------------------------------------------------------------------------------- /avatar/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avatarone/avatar-python/c6d74f85f63333e3031e1f5e208d3f90e316a9e4/avatar/util/__init__.py -------------------------------------------------------------------------------- /avatar/util/checksum.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class Crc8(): 4 | """ 5 | Implements the 1-wire CRC8 checksum. 6 | (The polynomial should be X^8 + X^5 + X^4 + X^0) 7 | """ 8 | R1 = [0x00, 0x5e, 0xbc, 0xe2, 0x61, 0x3f, 0xdd, 0x83, 9 | 0xc2, 0x9c, 0x7e, 0x20, 0xa3, 0xfd, 0x1f, 0x41] 10 | 11 | R2 = [0x00, 0x9d, 0x23, 0xbe, 0x46, 0xdb, 0x65, 0xf8, 12 | 0x8c, 0x11, 0xaf, 0x32, 0xca, 0x57, 0xe9, 0x74] 13 | 14 | def __init__(self, data = None): 15 | self.crc = 0 16 | if data: 17 | self.add_bytes(data) 18 | 19 | def add_bytes(self, data): 20 | for byte in data: 21 | x = (byte ^ self.crc) & 0xFF 22 | self.crc = (self.R1[x & 0xF] ^ self.R2[(x >> 4) & 0xF]) & 0xFF 23 | return self.crc 24 | 25 | def get_crc(self): 26 | return self.crc 27 | -------------------------------------------------------------------------------- /avatar/util/indexable_queue.py: -------------------------------------------------------------------------------- 1 | from queue import Queue 2 | 3 | class IndexableQueue(Queue): 4 | """ Taken from http://stackoverflow.com/questions/1293966/best-way-to-obtain-indexed-access-to-a-python-queue-thread-safe""" 5 | def __getitem__(self, index): 6 | with self.mutex: 7 | return self.queue[index] 8 | 9 | def find_and_remove(self, expr): 10 | with self.mutex: 11 | for item in self.queue: 12 | if expr(item): 13 | self.queue.remove(item) 14 | return item 15 | return None -------------------------------------------------------------------------------- /avatar/util/ostools.py: -------------------------------------------------------------------------------- 1 | import os 2 | import errno 3 | import random 4 | import socket 5 | 6 | def mkdir_p(path): 7 | try: 8 | os.makedirs(path) 9 | except OSError as exc: # Python >2.5 10 | if exc.errno == errno.EEXIST and os.path.isdir(path): 11 | pass 12 | else: raise 13 | 14 | 15 | def get_random_free_port(interface = '0.0.0.0'): 16 | while True: 17 | port = random.randint(20000, 65535) 18 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 19 | try: 20 | sock.bind((interface, port)) 21 | sock.close() 22 | return port 23 | except Exception as ex: 24 | raise ex 25 | -------------------------------------------------------------------------------- /avatar/util/processes.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Jun 26, 2013 3 | 4 | @author: Jonas Zaddach 5 | ''' 6 | import subprocess 7 | 8 | def get_process_list(): 9 | processes = [] 10 | ps_output = subprocess.check_output(["ps", "-A", "-w", "-w", "-o", "pid", "-o", "command"]) 11 | ps_output = ps_output.decode('latin-1') 12 | for line in ps_output.split("\n")[1:]: 13 | line = line.strip() 14 | if not line: 15 | continue 16 | pid = line[:line.find(" ")] 17 | cmd = line[line.find(" ") + 1:] 18 | processes.append({"pid": int(pid), "cmd": cmd}) 19 | 20 | return processes 21 | 22 | def find_processes(name): 23 | process_list = get_process_list() 24 | found_processes = [] 25 | 26 | for process in process_list: 27 | if process["cmd"].startswith(name): 28 | found_processes.append(process) 29 | return found_processes -------------------------------------------------------------------------------- /avatar/util/reference.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on May 2, 2013 3 | 4 | @author: Jonas Zaddach 5 | ''' 6 | class Reference(): 7 | def __init__(self, obj = None): 8 | self._obj = obj 9 | 10 | def set_value(self, obj): 11 | self._obj = obj 12 | 13 | def get_value(self): 14 | return self._obj -------------------------------------------------------------------------------- /avatar/util/socket_file.py: -------------------------------------------------------------------------------- 1 | class SocketFile(): 2 | def __init__(self, sock): 3 | self._sock = sock 4 | 5 | def read(self, num_bytes): 6 | return self._sock.recv(num_bytes) 7 | 8 | def write(self, data): 9 | if isinstance(data, str): 10 | raise Exception() 11 | self._sock.send(data) 12 | 13 | def fileno(self): 14 | return self._sock.fileno() 15 | 16 | def flush(self): 17 | pass 18 | 19 | # def readline(self): 20 | # data = self.read(1) 21 | # buffer = [] 22 | # while data[0] != 0xA and data[0] != 0xD: 23 | # buffer.append(data[0]) 24 | # data = self.read(1) 25 | # 26 | # buffer.append(data[0]) 27 | # return bytes(buffer) -------------------------------------------------------------------------------- /binary_translator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED (VERSION 2.8) 2 | PROJECT (lldc) 3 | 4 | SET (LLVM_FIND_REQUIRED TRUE) 5 | INCLUDE (${PROJECT_SOURCE_DIR}/cmake/FindLLVM.cmake) 6 | 7 | FIND_PACKAGE(PythonLibs 3.2 REQUIRED) 8 | 9 | INCLUDE_DIRECTORIES(${LLVM_INCLUDE_DIR} 10 | ${PROJECT_SOURCE_DIR}/include 11 | ${LLVM_OBJ_ROOT}/lib/Target/ARM 12 | ${LLVM_SRC_ROOT}/lib/Target/ARM/MCTargetDesc 13 | ${PYTHON_INCLUDE_PATH}) 14 | 15 | LINK_DIRECTORIES(${LLVM_LIB_DIR}) 16 | 17 | #SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LLVM_COMPILE_FLAGS} -std=c++11") 18 | SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LLVM_COMPILE_FLAGS} -fno-rtti") 19 | 20 | LLVM_GET_LIBRARIES (LLVM_LIBRARIES core mc x86Info x86Desc x86Disassembler x86AsmPrinter x86CodeGen armInfo armDesc armAsmPrinter armDisassembler armCodeGen mcDisassembler mcParser mcJit jit mc) 21 | MESSAGE ("Using LLVM libraries: ${LLVM_LIBRARIES}") 22 | SET (LLDC_SOURCE 23 | src/PathState.cpp 24 | src/FunctionCache.cpp 25 | src/BasicBlockCache.cpp 26 | src/ArmReverseTranslators.cpp 27 | src/ArrayMemoryObject.cpp 28 | src/util.cpp 29 | src/PathsManager.cpp 30 | src/InstructionDecoder.cpp 31 | src/ReverseTranslationConfiguration.cpp 32 | src/ProxyMemoryObject.cpp 33 | src/InstructionTranslationUnitCache.cpp 34 | src/RecordingMemoryManager.cpp 35 | src/InstrumentMemoryAccessPass.cpp 36 | src/c_interface.cpp) 37 | 38 | SET (BINARY_TRANSLATOR_SOURCE 39 | src/python_interface.c) 40 | 41 | ADD_LIBRARY(lldc STATIC ${LLDC_SOURCE}) 42 | TARGET_LINK_LIBRARIES(lldc ${LLVM_LIBRARIES} ${LLVM_LDFLAGS}) 43 | 44 | ADD_LIBRARY (binary_translator SHARED ${BINARY_TRANSLATOR_SOURCE}) 45 | #SET_TARGET_PROPERTIES(lldc PROPERTIES LINK_FLAGS ${LLVM_LDFLAGS}) 46 | #We don't want this pesky "lib" in front of our python library 47 | SET_TARGET_PROPERTIES(binary_translator PROPERTIES PREFIX "") 48 | IF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") 49 | #Python wants the libary's postfix to be .so instead of .dylib on MacOS 50 | SET_TARGET_PROPERTIES(binary_translator PROPERTIES SUFFIX ".so") 51 | ENDIF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") 52 | TARGET_LINK_LIBRARIES (binary_translator lldc ${PYTHON_LIBRARIES}) 53 | 54 | ADD_EXECUTABLE(bt_test test_translation.c) 55 | TARGET_LINK_LIBRARIES(bt_test lldc) 56 | -------------------------------------------------------------------------------- /binary_translator/cmake/FindLLVM.cmake: -------------------------------------------------------------------------------- 1 | # Detect LLVM and set various variable to link against the different component of LLVM 2 | # 3 | # NOTE: This is a modified version of the module originally found in the OpenGTL project 4 | # at www.opengtl.org 5 | # 6 | # LLVM_BIN_DIR : directory with LLVM binaries 7 | # LLVM_LIB_DIR : directory with LLVM library 8 | # LLVM_INCLUDE_DIR : directory with LLVM include 9 | # 10 | # LLVM_COMPILE_FLAGS : compile flags needed to build a program using LLVM headers 11 | # LLVM_LDFLAGS : ldflags needed to link 12 | # LLVM_LIBS_CORE : ldflags needed to link against a LLVM core library 13 | # LLVM_LIBS_JIT : ldflags needed to link against a LLVM JIT 14 | # LLVM_LIBS_JIT_OBJECTS : objects you need to add to your source when using LLVM JIT 15 | 16 | if (MSVC) 17 | set(LLVM_ROOT "C:/Program Files/LLVM") 18 | if (NOT IS_DIRECTORY ${LLVM_ROOT}) 19 | message(FATAL_ERROR "Could NOT find LLVM") 20 | endif () 21 | 22 | message(STATUS "Found LLVM: ${LLVM_ROOT}") 23 | set(LLVM_BIN_DIR ${LLVM_ROOT}/bin) 24 | set(LLVM_LIB_DIR ${LLVM_ROOT}/lib) 25 | set(LLVM_INCLUDE_DIR ${LLVM_ROOT}/include) 26 | 27 | set(LLVM_COMPILE_FLAGS "") 28 | set(LLVM_LDFLAGS "") 29 | set(LLVM_LIBS_CORE LLVMLinker LLVMArchive LLVMBitWriter LLVMBitReader LLVMInstrumentation LLVMScalarOpts LLVMipo LLVMTransformUtils LLVMipa LLVMAnalysis LLVMTarget LLVMMC LLVMCore LLVMSupport LLVMSystem) 30 | set(LLVM_LIBS_JIT LLVMX86AsmParser LLVMX86AsmPrinter LLVMX86CodeGen LLVMSelectionDAG LLVMAsmPrinter LLVMX86Info LLVMJIT LLVMExecutionEngine LLVMCodeGen LLVMScalarOpts LLVMTransformUtils LLVMipa LLVMAnalysis LLVMTarget LLVMMC LLVMCore LLVMSupport LLVMSystem) 31 | set(LLVM_LIBS_JIT_OBJECTS "") 32 | endif (MSVC) 33 | 34 | if (LLVM_INCLUDE_DIR) 35 | set(LLVM_FOUND TRUE) 36 | else (LLVM_INCLUDE_DIR) 37 | 38 | if (NOT LLVM_CONFIG_EXECUTABLE) 39 | find_program(LLVM_CONFIG_EXECUTABLE 40 | NAMES llvm-config 41 | PATHS 42 | ${LLVM_ROOT}/bin 43 | /opt/local/bin 44 | /opt/llvm/2.6/bin 45 | /opt/llvm/bin 46 | /usr/bin 47 | ) 48 | endif (NOT LLVM_CONFIG_EXECUTABLE) 49 | 50 | find_program(LLVM_GCC_EXECUTABLE 51 | NAMES llvm-gcc llvmgcc 52 | PATHS 53 | ${LLVM_ROOT}/bin 54 | /opt/local/bin 55 | /opt/llvm/2.6/bin 56 | /opt/llvm/bin 57 | /Developer/usr/bin 58 | /usr/lib/llvm/llvm/gcc-4.2/bin 59 | /usr/bin 60 | ) 61 | 62 | find_program(LLVM_GXX_EXECUTABLE 63 | NAMES llvm-g++ llvmg++ 64 | PATHS 65 | ${LLVM_ROOT}/bin 66 | /opt/local/bin 67 | /opt/llvm/2.6/bin 68 | /opt/llvm/bin 69 | /Developer/usr/bin 70 | /usr/lib/llvm/llvm/gcc-4.2/bin 71 | /usr/bin 72 | ) 73 | 74 | if(LLVM_GCC_EXECUTABLE) 75 | MESSAGE(STATUS "LLVM llvm-gcc found at: ${LLVM_GCC_EXECUTABLE}") 76 | #CMAKE_FORCE_C_COMPILER(${LLVM_GCC_EXECUTABLE} GNU) 77 | endif(LLVM_GCC_EXECUTABLE) 78 | 79 | if(LLVM_GXX_EXECUTABLE) 80 | MESSAGE(STATUS "LLVM llvm-g++ found at: ${LLVM_GXX_EXECUTABLE}") 81 | #CMAKE_FORCE_CXX_COMPILER(${LLVM_GXX_EXECUTABLE} GNU) 82 | endif(LLVM_GXX_EXECUTABLE) 83 | 84 | if(LLVM_CONFIG_EXECUTABLE) 85 | MESSAGE(STATUS "LLVM llvm-config found at: ${LLVM_CONFIG_EXECUTABLE}") 86 | else(LLVM_CONFIG_EXECUTABLE) 87 | MESSAGE(FATAL_ERROR "Could NOT find LLVM") 88 | endif(LLVM_CONFIG_EXECUTABLE) 89 | 90 | MACRO(FIND_LLVM_LIBS LLVM_CONFIG_EXECUTABLE _libname_ LIB_VAR OBJECT_VAR) 91 | exec_program( ${LLVM_CONFIG_EXECUTABLE} ARGS --libs ${_libname_} OUTPUT_VARIABLE ${LIB_VAR} ) 92 | STRING(REGEX MATCHALL "[^ ]*[.]o[ $]" ${OBJECT_VAR} ${${LIB_VAR}}) 93 | SEPARATE_ARGUMENTS(${OBJECT_VAR}) 94 | STRING(REGEX REPLACE "[^ ]*[.]o[ $]" "" ${LIB_VAR} ${${LIB_VAR}}) 95 | ENDMACRO(FIND_LLVM_LIBS) 96 | 97 | 98 | # this function borrowed from PlPlot, Copyright (C) 2006 Alan W. Irwin 99 | function(TRANSFORM_VERSION numerical_result version) 100 | # internal_version ignores everything in version after any character that 101 | # is not 0-9 or ".". This should take care of the case when there is 102 | # some non-numerical data in the patch version. 103 | #message(STATUS "DEBUG: version = ${version}") 104 | string(REGEX REPLACE "^([0-9.]+).*$" "\\1" internal_version ${version}) 105 | 106 | # internal_version is normally a period-delimited triplet string of the form 107 | # "major.minor.patch", but patch and/or minor could be missing. 108 | # Transform internal_version into a numerical result that can be compared. 109 | string(REGEX REPLACE "^([0-9]*).+$" "\\1" major ${internal_version}) 110 | string(REGEX REPLACE "^[0-9]*\\.([0-9]*).*$" "\\1" minor ${internal_version}) 111 | #string(REGEX REPLACE "^[0-9]*\\.[0-9]*\\.([0-9]*)$" "\\1" patch ${internal_version}) 112 | 113 | #if(NOT patch MATCHES "[0-9]+") 114 | # set(patch 0) 115 | #endif(NOT patch MATCHES "[0-9]+") 116 | set(patch 0) 117 | 118 | if(NOT minor MATCHES "[0-9]+") 119 | set(minor 0) 120 | endif(NOT minor MATCHES "[0-9]+") 121 | 122 | if(NOT major MATCHES "[0-9]+") 123 | set(major 0) 124 | endif(NOT major MATCHES "[0-9]+") 125 | #message(STATUS "DEBUG: internal_version = ${internal_version}") 126 | #message(STATUS "DEBUG: major = ${major}") 127 | #message(STATUS "DEBUG: minor= ${minor}") 128 | #message(STATUS "DEBUG: patch = ${patch}") 129 | math(EXPR internal_numerical_result 130 | #"${major}*1000000 + ${minor}*1000 + ${patch}" 131 | "${major}*1000000 + ${minor}*1000" 132 | ) 133 | #message(STATUS "DEBUG: ${numerical_result} = ${internal_numerical_result}") 134 | set(${numerical_result} ${internal_numerical_result} PARENT_SCOPE) 135 | endfunction(TRANSFORM_VERSION) 136 | 137 | 138 | exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --version OUTPUT_VARIABLE LLVM_STRING_VERSION ) 139 | MESSAGE(STATUS "LLVM version: " ${LLVM_STRING_VERSION}) 140 | transform_version(LLVM_VERSION ${LLVM_STRING_VERSION}) 141 | 142 | exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --bindir OUTPUT_VARIABLE LLVM_BIN_DIR ) 143 | exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --libdir OUTPUT_VARIABLE LLVM_LIB_DIR ) 144 | #MESSAGE(STATUS "LLVM lib dir: " ${LLVM_LIB_DIR}) 145 | exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --includedir OUTPUT_VARIABLE LLVM_INCLUDE_DIR ) 146 | 147 | 148 | exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --cxxflags OUTPUT_VARIABLE LLVM_COMPILE_FLAGS ) 149 | MESSAGE(STATUS "LLVM CXX flags: " ${LLVM_COMPILE_FLAGS}) 150 | exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --ldflags OUTPUT_VARIABLE LLVM_LDFLAGS ) 151 | MESSAGE(STATUS "LLVM LD flags: " ${LLVM_LDFLAGS}) 152 | exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --libs core ipa ipo instrumentation bitreader bitwriter linker OUTPUT_VARIABLE LLVM_LIBS_CORE ) 153 | MESSAGE(STATUS "LLVM core libs: " ${LLVM_LIBS_CORE}) 154 | IF(APPLE AND UNIVERSAL) 155 | FIND_LLVM_LIBS( ${LLVM_CONFIG_EXECUTABLE} "jit native x86 PowerPC ARM" LLVM_LIBS_JIT LLVM_LIBS_JIT_OBJECTS ) 156 | ELSE(APPLE AND UNIVERSAL) 157 | FIND_LLVM_LIBS( ${LLVM_CONFIG_EXECUTABLE} "jit native" LLVM_LIBS_JIT LLVM_LIBS_JIT_OBJECTS ) 158 | ENDIF(APPLE AND UNIVERSAL) 159 | MESSAGE(STATUS "LLVM JIT libs: " ${LLVM_LIBS_JIT}) 160 | MESSAGE(STATUS "LLVM JIT objs: " ${LLVM_LIBS_JIT_OBJECTS}) 161 | 162 | 163 | 164 | exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --obj-root OUTPUT_VARIABLE LLVM_OBJ_ROOT ) 165 | MESSAGE(STATUS "LLVM object root: " ${LLVM_OBJ_ROOT}) 166 | exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --src-root OUTPUT_VARIABLE LLVM_SRC_ROOT ) 167 | MESSAGE(STATUS "LLVM source root: " ${LLVM_SRC_ROOT}) 168 | 169 | if(LLVM_INCLUDE_DIR) 170 | set(LLVM_FOUND TRUE) 171 | endif(LLVM_INCLUDE_DIR) 172 | 173 | if(LLVM_FOUND) 174 | message(STATUS "Found LLVM: ${LLVM_INCLUDE_DIR}") 175 | else(LLVM_FOUND) 176 | if(LLVM_FIND_REQUIRED) 177 | message(FATAL_ERROR "Could NOT find LLVM") 178 | endif(LLVM_FIND_REQUIRED) 179 | endif(LLVM_FOUND) 180 | 181 | endif (LLVM_INCLUDE_DIR) 182 | 183 | 184 | # This is a variant intended for the final user: 185 | function(llvm_get_libraries OUT_VAR) 186 | STRING (REPLACE ";" " " COMPONENTS "${ARGN}") 187 | exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --libs "${COMPONENTS}" OUTPUT_VARIABLE LIB_NAMES) 188 | SET (${OUT_VAR} "${LIB_NAMES}" PARENT_SCOPE) 189 | endfunction(llvm_get_libraries) 190 | -------------------------------------------------------------------------------- /binary_translator/include/lldc/ArmReverseTranslators.h: -------------------------------------------------------------------------------- 1 | #ifndef _ARM_REVERSE_TRANSLATORS_H 2 | #define _ARM_REVERSE_TRANSLATORS_H 3 | 4 | #include "ReverseTranslationConfiguration.h" 5 | #include "ExtendedMCInst.h" 6 | 7 | void getArmReverseTranslators(std::map& translators); 8 | 9 | #endif /* _ARM_REVERSE_TRANSLATORS_H */ 10 | -------------------------------------------------------------------------------- /binary_translator/include/lldc/ArrayMemoryObject.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARRAY_MEMORY_OBJECT_H 2 | #define __ARRAY_MEMORY_OBJECT_H 3 | 4 | #include "llvm/Support/MemoryObject.h" 5 | 6 | class ArrayMemoryObject : public llvm::MemoryObject { 7 | private: 8 | uint8_t * data; 9 | size_t size; 10 | uint64_t base; 11 | public: 12 | ArrayMemoryObject(uint64_t base, size_t size); 13 | 14 | virtual uint64_t getBase() const; 15 | virtual uint64_t getExtent() const; 16 | virtual int readByte(uint64_t addr, uint8_t * byte) const; 17 | virtual ~ArrayMemoryObject(); 18 | uint8_t * getArray(); 19 | }; 20 | 21 | #endif /* __ARRAY_MEMORY_OBJECT_H */ 22 | -------------------------------------------------------------------------------- /binary_translator/include/lldc/BasicBlockCache.h: -------------------------------------------------------------------------------- 1 | #ifndef _BASIC_BLOCK_CACHE_H 2 | #define _BASIC_BLOCK_CACHE_H 3 | 4 | #include 5 | #include "llvm/IR/BasicBlock.h" 6 | #include "llvm/IR/Function.h" 7 | 8 | #include "ReverseTranslateBasicBlock.h" 9 | 10 | class PathState; 11 | 12 | class TranslatedBasicBlock : public ReverseTranslateBasicBlock { 13 | private: 14 | llvm::BasicBlock* bb; 15 | uint64_t pc_start; 16 | uint64_t pc_end; 17 | 18 | public: 19 | 20 | TranslatedBasicBlock(llvm::BasicBlock* bb, uint64_t pc_start, uint64_t pc_end) 21 | : bb(bb), pc_start(pc_start), pc_end(pc_end) 22 | { 23 | } 24 | 25 | virtual llvm::BasicBlock* getBasicBlock() { 26 | return this->bb; 27 | } 28 | 29 | uint64_t getStartProgramCounter() { 30 | return this->pc_start; 31 | } 32 | 33 | uint64_t getEndProgramCounter() { 34 | return this->pc_end; 35 | } 36 | 37 | virtual bool isTranslationFinished() { 38 | return true; 39 | } 40 | 41 | virtual ~TranslatedBasicBlock() { 42 | } 43 | 44 | }; 45 | 46 | /** 47 | * This is an interface for the basic block cache. 48 | * TODO: Currently the implementation is here, should be moved out 49 | * into its own subclass. 50 | */ 51 | 52 | class BasicBlockCache { 53 | typedef std::map PcToBBMap; 54 | typedef std::map BasicBlockCacheMap; 55 | 56 | BasicBlockCacheMap basicBlockCache; 57 | llvm::LLVMContext& context; 58 | 59 | public: 60 | BasicBlockCache(llvm::LLVMContext& context); 61 | 62 | /** 63 | * Insert a new basic block in the cache. 64 | */ 65 | void insert(PathState* state, uint64_t pc_start, uint64_t pc_end, llvm::BasicBlock * bb); 66 | 67 | /** 68 | * Find a basic block from its function and entry program counter. 69 | */ 70 | TranslatedBasicBlock * find(PathState* state, uint64_t pc); 71 | 72 | TranslatedBasicBlock * find(llvm::Function* function, uint64_t pc); 73 | 74 | /** 75 | * Has to be called whenever data is written to (code) memory. 76 | */ 77 | void invalidateBasicBlocks(uint64_t pc); 78 | }; 79 | 80 | #endif /* _BASIC_BLOCK_CACHE_H */ 81 | -------------------------------------------------------------------------------- /binary_translator/include/lldc/ExtendedMCInst.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXTENDED_MC_INST_H 2 | #define _EXTENDED_MC_INST_H 3 | 4 | #include "llvm/MC/MCInst.h" 5 | #include "llvm/IR/BasicBlock.h" 6 | 7 | class ExtendedMCInst : public llvm::MCInst { 8 | public: 9 | uint64_t pc; 10 | uint64_t size; 11 | 12 | public: 13 | ExtendedMCInst() 14 | : pc(0), size(0) 15 | { 16 | } 17 | 18 | void setProgramCounter(uint64_t pc) { 19 | this->pc = pc; 20 | } 21 | 22 | uint64_t getProgramCounter() { 23 | return pc; 24 | } 25 | 26 | void setSize(uint64_t size) { 27 | this->size = size; 28 | } 29 | 30 | uint64_t getSize() { 31 | return size; 32 | } 33 | }; 34 | 35 | #endif /* _EXTENDED_MC_INST_H */ 36 | -------------------------------------------------------------------------------- /binary_translator/include/lldc/FunctionCache.h: -------------------------------------------------------------------------------- 1 | #ifndef _FUNCTION_CACHE_H 2 | #define _FUNCTION_CACHE_H 3 | 4 | #include 5 | #include "llvm/IR/Function.h" 6 | #include "llvm/IR/Module.h" 7 | 8 | class ReverseTranslationConfiguration; 9 | 10 | class FunctionCache { 11 | private: 12 | std::map cache; 13 | 14 | public: 15 | void insertFunction(uint64_t pc, llvm::Function* function); 16 | 17 | llvm::Function* getOrCreateFunction(ReverseTranslationConfiguration* config, llvm::Module* module, uint64_t function_address); 18 | }; 19 | 20 | #endif /* _FUNCTION_CACHE_H */ 21 | -------------------------------------------------------------------------------- /binary_translator/include/lldc/GeneratedBasicBlocks.h: -------------------------------------------------------------------------------- 1 | #ifndef _GENERATED_BASIC_BLOCKS_H 2 | #define _GENERATED_BASIC_BLOCKS_H 3 | 4 | #include 5 | #include "llvm/IR/BasicBlock.h" 6 | 7 | /** 8 | * This is the class in which the resulting basic blocks from translating one instruction are returned. 9 | */ 10 | 11 | class GeneratedBasicBlocks 12 | { 13 | llvm::BasicBlock * currentBB; 14 | uint64_t currentPC; //Next instruction pointer in the current BB 15 | llvm::BasicBlock * nextBB; 16 | uint64_t nextPC; //Next instruction pointer in the next BB 17 | llvm::BasicBlock * branchBB; 18 | uint64_t branchPC; //Next instruction pointer in the branch BB 19 | llvm::BasicBlock * exceptionBB; 20 | uint64_t exceptionPC; //Next instruction pointer in the exception BB 21 | 22 | public: 23 | GeneratedBasicBlocks() {} 24 | 25 | llvm::BasicBlock * getCurrentBB() {return this->currentBB;} 26 | llvm::BasicBlock * getNextBB() {return this->nextBB;} 27 | llvm::BasicBlock * getBranchBB() {return this->branchBB;} 28 | llvm::BasicBlock * getExceptionBB() {return this->exceptionBB;} 29 | uint64_t getCurrentBBProgramCounter() {return this->currentPC;} 30 | uint64_t getNextBBProgramCounter() {return this->nextPC;} 31 | uint64_t getBranchBBProgramCounter() {return this->branchPC;} 32 | uint64_t getExceptionBBProgramCounter() {return this->exceptionPC;} 33 | 34 | void setCurrentBB(uint64_t pc, llvm::BasicBlock * bb) { 35 | this->currentBB = bb; 36 | this->currentPC = pc; 37 | } 38 | 39 | void setNextBB(uint64_t pc, llvm::BasicBlock * bb) { 40 | this->nextBB = bb; 41 | this->nextPC = pc; 42 | } 43 | 44 | void setBranchBB(uint64_t pc, llvm::BasicBlock * bb) { 45 | this->branchBB = bb; 46 | this->branchPC = pc; 47 | } 48 | 49 | void setExceptionBB(uint64_t pc, llvm::BasicBlock * bb) { 50 | this->exceptionBB = bb; 51 | this->exceptionPC = pc; 52 | } 53 | }; 54 | 55 | 56 | #endif /* _GENERATED_BASIC_BLOCKS_H */ 57 | -------------------------------------------------------------------------------- /binary_translator/include/lldc/InstructionDecoder.h: -------------------------------------------------------------------------------- 1 | #ifndef __INSTRUCTION_DECODER_H 2 | #define __INSTRUCTION_DECODER_H 3 | 4 | #include "lldc/ReverseTranslationConfiguration.h" 5 | #include "lldc/ReverseTranslateBasicBlock.h" 6 | #include "lldc/SystemInformation.h" 7 | #include "lldc/BasicBlockCache.h" 8 | 9 | #include "llvm/Support/MemoryObject.h" 10 | #include "llvm/Support/TargetSelect.h" 11 | #include "llvm/Support/raw_ostream.h" 12 | 13 | #include 14 | 15 | class UnfinishedInstructionTranslationUnit; 16 | 17 | class Ranges 18 | { 19 | std::list > ranges; 20 | 21 | public: 22 | Ranges(std::list >& ranges) : ranges(ranges) {} 23 | 24 | bool is_in_range(uint64_t val) { 25 | for (std::list >::iterator itr = ranges.begin(); 26 | itr != ranges.end(); 27 | itr++) 28 | { 29 | if (val >= itr->first && val < itr->second) 30 | return true; 31 | } 32 | 33 | return false; 34 | } 35 | }; 36 | 37 | class CompiledCode 38 | { 39 | uint8_t* data; 40 | unsigned size; 41 | uint64_t address; 42 | public: 43 | CompiledCode(uint64_t address, uint8_t * data, unsigned size) 44 | : data(data), size(size), address(address) 45 | { 46 | this->data = new uint8_t[size]; 47 | memcpy(this->data, data, size); 48 | } 49 | 50 | unsigned getSize() {return size;} 51 | uint8_t* getData() {return data;} 52 | uint64_t getAddress() {return address;} 53 | virtual ~CompiledCode() 54 | { 55 | if (data) 56 | delete[] data; 57 | } 58 | }; 59 | 60 | 61 | class BinaryTranslator { 62 | private: 63 | ReverseTranslationConfiguration* config; 64 | llvm::MemoryObject* memory; 65 | llvm::MCInstrInfo* thumbInstrInfo; 66 | llvm::MCRegisterInfo* thumbRegInfo; 67 | llvm::MCSubtargetInfo* thumbSubtarget; 68 | llvm::MCAsmInfo* thumbAsmInfo; 69 | const llvm::MCDisassembler* thumbDisassembler; 70 | llvm::MCInstrInfo* armInstrInfo; 71 | llvm::MCRegisterInfo* armRegInfo; 72 | llvm::MCSubtargetInfo* armSubtarget; 73 | llvm::MCAsmInfo* armAsmInfo; 74 | const llvm::MCDisassembler* armDisassembler; 75 | llvm::MCInstPrinter* thumbInstPrinter; 76 | SystemInformation* sysInfo; 77 | // BasicBlockCache> basicBlockCache; 78 | // PathsManager* mgr; 79 | llvm::Module* module; 80 | llvm::Function* wrapper_function; 81 | const llvm::Target * thumbTarget; 82 | llvm::Value* instrumentationReadHandler; 83 | llvm::Value* instrumentationWriteHandler; 84 | 85 | void genCodeEntry(uint64_t pc); 86 | uint64_t entry_pc; 87 | bool is_debug; 88 | public: 89 | BinaryTranslator(std::string architecture, llvm::MemoryObject* memory, std::list& registerDescription, uint64_t entry_pc, llvm::StringRef module_name = "dummy_module"); 90 | virtual ~BinaryTranslator() throw(); 91 | void translate(Ranges& ranges); 92 | void translateSingleInstruction(UnfinishedInstructionTranslationUnit* unit); 93 | void genCodeExit(UnfinishedInstructionTranslationUnit* unit); 94 | void dumpIR(llvm::raw_ostream* out = NULL); 95 | CompiledCode* compile(); 96 | void instrumentMemoryAccess(); 97 | void setDebug(bool debug) {this->is_debug = debug;} 98 | }; 99 | 100 | #endif /* __INSTRUCTION_DECODER_H */ 101 | -------------------------------------------------------------------------------- /binary_translator/include/lldc/InstructionTranslationUnitCache.h: -------------------------------------------------------------------------------- 1 | #ifndef _INSTRUCTION_TRANSLATION_UNIT_CACHE_H 2 | #define _INSTRUCTION_TRANSLATION_UNIT_CACHE_H 3 | 4 | #include 5 | #include "llvm/IR/Instructions.h" 6 | #include "llvm/MC/MCInst.h" 7 | 8 | #include "lldc/ReverseTranslationConfiguration.h" 9 | 10 | /** 11 | * A translated instruction consists of at least one basic block, but can be composed of several 12 | * (in case of conditional assembler instructions). 13 | * Each instruction starts with a phi node for every register and flag. 14 | * The entry basic block of the instruction is labelled with the pc value as hex string, all further 15 | * blocks are labelled with the pc hex string plus an underscore and some number. 16 | * A translated instruction can only belong to one function (this might pose a problem if you start 17 | * translating in the middle of a function that is recursive). 18 | */ 19 | class InstructionTranslationUnit 20 | { 21 | friend class InstructionTranslationUnitCache; 22 | 23 | std::map< unsigned, llvm::PHINode* > phi_nodes; 24 | uint64_t pc; 25 | llvm::BasicBlock* head_bb; 26 | bool is_finished; 27 | unsigned instruction_set; 28 | llvm::MCInst* original_instruction; 29 | llvm::Function* function; 30 | 31 | public: 32 | InstructionTranslationUnit() 33 | : pc(0), head_bb(0), is_finished(false), instruction_set(0), original_instruction(0), function(0) 34 | { 35 | } 36 | 37 | void addIncoming(const std::map< unsigned, llvm::Value* >& values, llvm::BasicBlock* predecessor); 38 | 39 | uint64_t getProgramCounter() {return pc;} 40 | llvm::BasicBlock* getHead() {return head_bb;} 41 | unsigned getInstructionSet() {return instruction_set;} 42 | 43 | llvm::Function* getFunction() {return function;} 44 | }; 45 | 46 | class UnfinishedInstructionTranslationUnit 47 | { 48 | InstructionTranslationUnit& instruction_translation_unit; 49 | std::map< unsigned, llvm::Value* > values; 50 | llvm::BasicBlock* tail_bb; 51 | public: 52 | UnfinishedInstructionTranslationUnit(InstructionTranslationUnit& unit, const std::map< unsigned, llvm::Value* >& values); 53 | void translation_finished(void); 54 | bool operator==(const UnfinishedInstructionTranslationUnit& other); 55 | InstructionTranslationUnit& getTranslationUnit() {return instruction_translation_unit;} 56 | std::map< unsigned, llvm::Value* >& getValues() {return values;} 57 | llvm::Value* getValue(unsigned id) {return values[id];} 58 | void setValue(unsigned id, llvm::Value* val) {values[id] = val;} 59 | }; 60 | 61 | class InstructionTranslationUnitCache 62 | { 63 | std::map< llvm::Function*, std::map< uint64_t, InstructionTranslationUnit > > instruction_translation_unit_cache; 64 | std::list< UnfinishedInstructionTranslationUnit* > unfinished_instruction_translation_units; 65 | 66 | private: 67 | InstructionTranslationUnit* find(llvm::Function* function, uint64_t pc); 68 | InstructionTranslationUnit* create(ReverseTranslationConfiguration&, llvm::Function*, uint64_t); 69 | 70 | public: 71 | InstructionTranslationUnit* find_create(ReverseTranslationConfiguration& config, llvm::Function* function, uint64_t pc, const std::map< unsigned, llvm::Value* >& predecessor_values, llvm::BasicBlock *predecessor_bb, bool terminate_last_block = true); 72 | UnfinishedInstructionTranslationUnit* get_next_unfinished_translation_unit(); 73 | bool has_more_unfinished_translation_units(); 74 | static InstructionTranslationUnitCache& getInstance(); 75 | }; 76 | 77 | #endif /* _INSTRUCTION_TRANSLATION_UNIT_CACHE_H */ -------------------------------------------------------------------------------- /binary_translator/include/lldc/InstrumentMemoryAccessPass.h: -------------------------------------------------------------------------------- 1 | #ifndef _INSTRUMENT_MEMORY_ACCESS_PASS_H 2 | #define _INSTRUMENT_MEMORY_ACCESS_PASS_H 3 | 4 | #include "llvm/Pass.h" 5 | #include "llvm/IR/Function.h" 6 | #include "llvm/Support/raw_ostream.h" 7 | 8 | struct InstrumentMemoryAccessPass : public llvm::BasicBlockPass 9 | { 10 | private: 11 | llvm::Value* read_handler; 12 | llvm::Value* write_handler; 13 | public: 14 | InstrumentMemoryAccessPass(char& pid, llvm::Value* read_handler, llvm::Value* write_handler); 15 | virtual bool doInitialization(llvm::Function &F); 16 | virtual bool runOnBasicBlock(llvm::BasicBlock &BB); 17 | virtual bool doFinalization(llvm::Function &F); 18 | virtual void getAnalysisUsage(llvm::AnalysisUsage &Info) const; 19 | virtual const char * getPassName() const; 20 | }; 21 | 22 | #endif /* _INSTRUMENT_MEMORY_ACCESS_PASS_H */ -------------------------------------------------------------------------------- /binary_translator/include/lldc/LLVMArmInstructions.h: -------------------------------------------------------------------------------- 1 | #ifndef _LLVM_ARM_INSTRUCTIONS_H 2 | #define _LLVM_ARM_INSTRUCTIONS_H 3 | 4 | #define GET_INSTRINFO_ENUM 5 | #include "ARMBaseInfo.h" 6 | 7 | #endif /* _LLVM_ARM_INSTRUCTIONS_H */ -------------------------------------------------------------------------------- /binary_translator/include/lldc/LLVMArmRegisters.h: -------------------------------------------------------------------------------- 1 | #ifndef _ARM_REGISTERS_H 2 | #define _ARM_REGISTERS_H 3 | 4 | #define GET_REGINFO_ENUM 5 | #include "ARMBaseInfo.h" 6 | 7 | namespace llvm { 8 | namespace ARM { 9 | static const unsigned FLAG_V = 0x101c; 10 | static const unsigned FLAG_C = 0x101d; 11 | static const unsigned FLAG_Z = 0x101e; 12 | static const unsigned FLAG_N = 0x101f; 13 | } 14 | } 15 | 16 | #endif /* _ARM_REGISTERS_H */ -------------------------------------------------------------------------------- /binary_translator/include/lldc/NextInstructions.h: -------------------------------------------------------------------------------- 1 | #ifndef _NEXT_INSTRUCTIONS_H 2 | #define _NEXT_INSTRUCTIONS_H 3 | 4 | #define MAX_NEXT_INSTRUCTIONS 5 5 | 6 | class ReverseTranslateBasicBlock; 7 | 8 | class NextInstructions 9 | { 10 | public: 11 | enum FlowType { 12 | FLOW_NONE, 13 | FLOW_NORMAL, 14 | FLOW_BRANCH, 15 | FLOW_CALL, 16 | FLOW_RETURN, 17 | FLOW_CONDITIONAL_BRANCH, 18 | FLOW_CONDITIONAL_CALL, 19 | FLOW_CONDITIONAL_RETURN, 20 | FLOW_CONDITIONAL_INSTRUCTION, 21 | FLOW_EXCEPTION 22 | }; 23 | 24 | private: 25 | struct NextInstruction { 26 | FlowType flow_type; 27 | uint64_t pc; 28 | ReverseTranslateBasicBlock* bb; 29 | }; 30 | 31 | struct NextInstruction nextInstructions[MAX_NEXT_INSTRUCTIONS]; 32 | unsigned numNextInstructions; 33 | 34 | public: 35 | NextInstructions() 36 | : numNextInstructions(0) { 37 | } 38 | 39 | void addNextInstruction(FlowType flow_type, uint64_t pc, ReverseTranslateBasicBlock* bb) { 40 | this->nextInstructions[this->numNextInstructions].pc = pc; 41 | this->nextInstructions[this->numNextInstructions].flow_type = flow_type; 42 | this->nextInstructions[this->numNextInstructions].bb = bb; 43 | this->numNextInstructions += 1; 44 | } 45 | 46 | uint64_t getProgramCounter(unsigned idx) { 47 | return this->nextInstructions[idx].pc; 48 | } 49 | 50 | FlowType getFlowType(unsigned idx) { 51 | return this->nextInstructions[idx].flow_type; 52 | } 53 | 54 | //TODO: Rename, does not return a BB 55 | ReverseTranslateBasicBlock* getBasicBlock(unsigned idx) { 56 | return this->nextInstructions[idx].bb; 57 | } 58 | 59 | unsigned getNumNextInstructions() { 60 | return this->numNextInstructions; 61 | } 62 | 63 | void clear() { 64 | this->numNextInstructions = 0; 65 | } 66 | 67 | bool endsBasicBlock() { 68 | for (unsigned i = 0; i < this->getNumNextInstructions(); i++) 69 | if (this->getFlowType(i) != NextInstructions::FLOW_NORMAL && 70 | this->getFlowType(i) != NextInstructions::FLOW_CALL) 71 | { 72 | return true; 73 | } 74 | return false; 75 | } 76 | }; 77 | 78 | #endif /* _NEXT_INSTRUCTIONS_H */ 79 | -------------------------------------------------------------------------------- /binary_translator/include/lldc/PathState.h: -------------------------------------------------------------------------------- 1 | #ifndef _BASIC_BLOCK_TRANSLATION_STATE_H 2 | #define _BASIC_BLOCK_TRANSLATION_STATE_H 3 | 4 | #include "llvm/IR/BasicBlock.h" 5 | #include "llvm/IR/Module.h" 6 | #include "llvm/IR/Function.h" 7 | #include "llvm/IR/IRBuilder.h" 8 | 9 | #include "util.h" 10 | #include "ReverseTranslateBasicBlock.h" 11 | #include 12 | 13 | class BasicBlockCache; 14 | class ReverseTranslationConfiguration; 15 | 16 | // class StackState { 17 | // private: 18 | // std::list stack; 19 | // public: 20 | // StackState() { 21 | // } 22 | // 23 | // StackState(StackState& other) { 24 | // this->stack = other.stack; 25 | // } 26 | // 27 | // void push(llvm::Value* val) { 28 | // stack.push_back(val); 29 | // } 30 | // 31 | // llvm::Value* pop() { 32 | // llvm::Value* val = stack.back(); 33 | // stack.pop_back(); 34 | // return val; 35 | // } 36 | // 37 | // void setStackElement(unsigned idx) { 38 | // return stack[stack.size() - 1 - idx]; 39 | // */} 40 | // }; 41 | 42 | 43 | /** 44 | * This class encapsules the translation state of a single basic block. 45 | * It only exists while a basic block has not yet been completely translated, 46 | * afterwards the basic block information is managed by the basic block cache. 47 | */ 48 | class PathState : public ReverseTranslateBasicBlock 49 | { 50 | friend class PathsManager; 51 | private: 52 | /** The actual basic block */ 53 | std::list bbs; 54 | /** The LLVM Module in which the basic block will be created. */ 55 | llvm::Module* mod; 56 | /** Program counter at the beginning of the basic block */ 57 | uint64_t start_pc; 58 | /** The program counter at the current translation point */ 59 | uint64_t pc; 60 | /** The registers at the current translation point */ 61 | std::map values; 62 | /**The stack's state.*/ 63 | // StackState stack; 64 | /** TODO: Arm specific, should go somewhere else */ 65 | bool thumb; 66 | 67 | public: 68 | PathState(llvm::BasicBlock* bb, llvm::Module* mod); 69 | PathState(); 70 | 71 | void init(llvm::BasicBlock* bb, 72 | llvm::Module* mod, 73 | uint64_t start_pc, 74 | std::map& values, 75 | bool thumb = true); 76 | 77 | llvm::LLVMContext& getContext(); 78 | 79 | virtual llvm::BasicBlock* getBasicBlock(); 80 | 81 | llvm::Module* getModule(); 82 | 83 | llvm::Function* getFunction(); 84 | 85 | uint64_t getStartProgramCounter(); 86 | 87 | void setProgramCounter(uint64_t pc); 88 | 89 | uint64_t getProgramCounter(); 90 | 91 | void setRegister(unsigned idx, llvm::Value* val); 92 | 93 | void setThumb(bool val); 94 | 95 | bool isThumb(); 96 | 97 | llvm::Value* getRegister(unsigned idx); 98 | 99 | void setCondition(unsigned idx, llvm::Value* val); 100 | 101 | llvm::Value* getCondition(unsigned idx); 102 | 103 | // StackState& getStackState() {return stack;} 104 | 105 | /** 106 | * Call this in the very end when the basic block is finished and all it successor 107 | * translation states have been generated to do some cleanup. 108 | */ 109 | void translationFinished(ReverseTranslationConfiguration* config, uint64_t end_pc); 110 | 111 | void instructionFinished(ReverseTranslationConfiguration* config, uint64_t next_pc); 112 | 113 | llvm::Value* getRegisterStructPtr(); 114 | 115 | void storeRegisters(); 116 | 117 | void loadRegisters(); 118 | 119 | virtual bool isTranslationFinished(); 120 | 121 | virtual ~PathState(); 122 | }; 123 | 124 | #endif /* _BASIC_BLOCK_TRANSLATION_STATE_H */ 125 | -------------------------------------------------------------------------------- /binary_translator/include/lldc/PathsManager.h: -------------------------------------------------------------------------------- 1 | #ifndef _PATHS_MANAGER_H 2 | #define _PATHS_MANAGER_H 3 | 4 | #include 5 | #include 6 | 7 | #include "llvm/IR/LLVMContext.h" 8 | #include "llvm/IR/Function.h" 9 | #include "llvm/IR/Value.h" 10 | 11 | #include "lldc/BasicBlockCache.h" 12 | #include "lldc/PathState.h" 13 | #include "lldc/ReverseTranslateBasicBlock.h" 14 | 15 | 16 | class PathsManager { 17 | std::list freeStates; 18 | std::list usedStates; 19 | BasicBlockCache* cache; 20 | public: 21 | PathsManager(BasicBlockCache* cache); 22 | 23 | BasicBlockCache* getBasicBlockCache() { 24 | return this->cache; 25 | } 26 | 27 | PathState* getUnfinishedPath(); 28 | 29 | PathState* createPath(PathState* previous, uint64_t pc); 30 | 31 | PathState* createPath(PathState* previous, 32 | llvm::Function* func, 33 | uint64_t start_pc) ; 34 | 35 | PathState* createPath(llvm::LLVMContext& context, 36 | llvm::Module* mod, 37 | llvm::Function* func, 38 | uint64_t start_pc, 39 | std::map& values) ; 40 | 41 | ReverseTranslateBasicBlock* getOrCreateReverseTranslateBasicBlock(PathState* previous, uint64_t pc); 42 | ReverseTranslateBasicBlock* getReverseTranslateBasicBlock(llvm::Function* function, uint64_t pc); 43 | void destroyPath(PathState* state); 44 | 45 | }; 46 | 47 | #endif /* _PATHS_MANAGER_H */ -------------------------------------------------------------------------------- /binary_translator/include/lldc/ProxyMemoryObject.h: -------------------------------------------------------------------------------- 1 | #ifndef __PROXY_MEMORY_OBJECT_H 2 | #define __PROXY_MEMORY_OBJECT_H 3 | 4 | #include 5 | #include "llvm/Support/MemoryObject.h" 6 | 7 | typedef unsigned (*ReadCodeMemoryFunc)(void *opaque, uint64_t address, unsigned size, uint8_t *buffer); 8 | 9 | class ProxyMemoryObject : public llvm::MemoryObject { 10 | private: 11 | void *opaque; 12 | ReadCodeMemoryFunc read_func; 13 | size_t size; 14 | uint64_t base; 15 | public: 16 | ProxyMemoryObject(ReadCodeMemoryFunc read_func, void * opaque, uint64_t base = 0, size_t size = 0xFFFFFFFF); 17 | 18 | virtual uint64_t getBase() const; 19 | virtual uint64_t getExtent() const; 20 | virtual int readByte(uint64_t addr, uint8_t * byte) const; 21 | virtual int readBytes(uint64_t addr, uint64_t size, uint8_t * byte) const; 22 | virtual ~ProxyMemoryObject(); 23 | }; 24 | 25 | #endif /* __PROXY_MEMORY_OBJECT_H */ 26 | -------------------------------------------------------------------------------- /binary_translator/include/lldc/RecordingMemoryManager.h: -------------------------------------------------------------------------------- 1 | //===- RecordingMemoryManager.h - LLI MCJIT recording memory manager ------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This memory manager allocates local storage and keeps a record of each 11 | // allocation. Iterators are provided for all data and code allocations. 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #ifndef RECORDINGMEMORYMANAGER_H 16 | #define RECORDINGMEMORYMANAGER_H 17 | 18 | #include "llvm/ADT/SmallVector.h" 19 | #include "llvm/ExecutionEngine/JITMemoryManager.h" 20 | #include "llvm/Support/ErrorHandling.h" 21 | #include "llvm/Support/Memory.h" 22 | #include 23 | 24 | namespace llvm { 25 | 26 | class RecordingMemoryManager : public JITMemoryManager { 27 | public: 28 | typedef std::pair Allocation; 29 | 30 | private: 31 | SmallVector AllocatedDataMem; 32 | SmallVector AllocatedCodeMem; 33 | 34 | // FIXME: This is part of a work around to keep sections near one another 35 | // when MCJIT performs relocations after code emission but before 36 | // the generated code is moved to the remote target. 37 | sys::MemoryBlock Near; 38 | sys::MemoryBlock allocateSection(uintptr_t Size); 39 | 40 | public: 41 | RecordingMemoryManager() {} 42 | virtual ~RecordingMemoryManager(); 43 | 44 | typedef SmallVectorImpl::const_iterator const_data_iterator; 45 | typedef SmallVectorImpl::const_iterator const_code_iterator; 46 | 47 | const_data_iterator data_begin() const { return AllocatedDataMem.begin(); } 48 | const_data_iterator data_end() const { return AllocatedDataMem.end(); } 49 | const_code_iterator code_begin() const { return AllocatedCodeMem.begin(); } 50 | const_code_iterator code_end() const { return AllocatedCodeMem.end(); } 51 | 52 | uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, 53 | unsigned SectionID); 54 | 55 | uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, 56 | unsigned SectionID, bool IsReadOnly); 57 | 58 | void *getPointerToNamedFunction(const std::string &Name, 59 | bool AbortOnFailure = true); 60 | 61 | bool finalizeMemory(std::string *ErrMsg) { return false; } 62 | 63 | // The following obsolete JITMemoryManager calls are stubbed out for 64 | // this model. 65 | void setMemoryWritable(); 66 | void setMemoryExecutable(); 67 | void setPoisonMemory(bool poison); 68 | void AllocateGOT(); 69 | uint8_t *getGOTBase() const; 70 | uint8_t *startFunctionBody(const Function *F, uintptr_t &ActualSize); 71 | uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize, 72 | unsigned Alignment); 73 | void endFunctionBody(const Function *F, uint8_t *FunctionStart, 74 | uint8_t *FunctionEnd); 75 | uint8_t *allocateSpace(intptr_t Size, unsigned Alignment); 76 | uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment); 77 | void deallocateFunctionBody(void *Body); 78 | virtual bool applyPermissions(std::string*); 79 | }; 80 | 81 | } // end namespace llvm 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /binary_translator/include/lldc/ReverseTranslateBasicBlock.h: -------------------------------------------------------------------------------- 1 | #ifndef _REVERSE_TRANSLATE_BASIC_BLOCK_H 2 | #define _REVERSE_TRANSLATE_BASIC_BLOCK_H 3 | 4 | #include "llvm/IR/BasicBlock.h" 5 | 6 | class ReverseTranslateBasicBlock { 7 | public: 8 | virtual bool isTranslationFinished() = 0; 9 | virtual llvm::BasicBlock* getBasicBlock() = 0; 10 | virtual ~ReverseTranslateBasicBlock() { 11 | } 12 | }; 13 | 14 | #endif /* _REVERSE_TRANSLATE_BASIC_BLOCK_H */ 15 | -------------------------------------------------------------------------------- /binary_translator/include/lldc/ReverseTranslationConfiguration.h: -------------------------------------------------------------------------------- 1 | #ifndef _REVERSE_TRANSLATION_CONFIGURATION 2 | #define _REVERSE_TRANSLATION_CONFIGURATION 3 | 4 | #include "llvm/Support/MemoryObject.h" 5 | #include "llvm/MC/MCDisassembler.h" 6 | #include "llvm/Support/TargetRegistry.h" 7 | 8 | #include "SystemInformation.h" 9 | #include "ExtendedMCInst.h" 10 | #include "NextInstructions.h" 11 | #include "ReverseTranslatorExceptions.h" 12 | #include "FunctionCache.h" 13 | 14 | class ReverseTranslationConfiguration; 15 | class ReverseTranslationState; 16 | class PathsManager; 17 | class PathState; 18 | class UnfinishedInstructionTranslationUnit; 19 | 20 | typedef void (*ReverseInstructionTranslatorFunction)(ExtendedMCInst& instruction, ReverseTranslationConfiguration& config, UnfinishedInstructionTranslationUnit* unit, llvm::MemoryObject* memory); 21 | 22 | class ValueInformation 23 | { 24 | std::string name; 25 | unsigned id; 26 | llvm::Type* type; 27 | public: 28 | ValueInformation(std::string name, unsigned id, llvm::Type* type) 29 | : name(name), id(id), type(type) 30 | { 31 | } 32 | 33 | const std::string& getName() const {return name;} 34 | unsigned getId() const {return id;} 35 | llvm::Type* getType() const {return type;} 36 | }; 37 | 38 | class ReverseTranslationConfiguration 39 | { 40 | llvm::LLVMContext& llvmContext; //< Stored here just for our convenience 41 | const llvm::MCDisassembler* thumbDisassembler; 42 | const llvm::MCDisassembler* armDisassembler; 43 | const llvm::Target* target; 44 | llvm::StructType* instrumentation_struct_ty; 45 | SystemInformation* sys_info; 46 | std::map instruction_translators; 47 | PathsManager* basicBlockTranslationStateManager; 48 | FunctionCache functionCache; 49 | public: 50 | ReverseTranslationConfiguration(llvm::LLVMContext& llvmContext, const llvm::MCDisassembler* thumbDisassembler, 51 | const llvm::MCDisassembler* armDisassembler, 52 | const llvm::Target* target, 53 | llvm::StructType* instrumentation_struct_ty, SystemInformation* sys_info, 54 | PathsManager* mgr); 55 | 56 | const llvm::MCDisassembler* getDisassembler(unsigned instruction_set); 57 | 58 | llvm::LLVMContext& getLLVMContext(); 59 | 60 | const llvm::Target* getTarget(PathState* state); 61 | 62 | SystemInformation* getSystemInformation(); 63 | 64 | llvm::StructType* getInstrumentationStructTy(); 65 | 66 | ReverseInstructionTranslatorFunction getReverseInstructionTranslator(ExtendedMCInst& instruction); 67 | 68 | std::map& getInstructionTranslators(); 69 | 70 | PathsManager* getBasicBlockTranslationStateManager(); 71 | 72 | FunctionCache& getFunctionCache(); 73 | 74 | const std::list& getValueInformation(); 75 | }; 76 | 77 | #endif /* _REVERSE_TRANSLATION_CONFIGURATION */ 78 | -------------------------------------------------------------------------------- /binary_translator/include/lldc/ReverseTranslatorExceptions.h: -------------------------------------------------------------------------------- 1 | #ifndef _REVERSE_TRANSLATOR_EXCEPTIONS_H 2 | #define _REVERSE_TRANSLATOR_EXCEPTIONS_H 3 | 4 | class Exception : public std::exception 5 | { 6 | std::string message; 7 | public: 8 | Exception(std::string message) : message(message) {} 9 | virtual const char * what() const throw() {return message.c_str();} 10 | virtual ~Exception() throw() {} 11 | }; 12 | 13 | class DisassemblerException : public Exception 14 | { 15 | uint64_t pc; 16 | 17 | public: 18 | DisassemblerException(uint64_t pc) : Exception("Disassembler exception"), pc(pc) {} 19 | uint64_t getProgramCounter() {return pc;} 20 | virtual ~DisassemblerException() throw() {} 21 | }; 22 | 23 | class LLVMException : public Exception 24 | { 25 | public: 26 | LLVMException(std::string description) : Exception(description) {} 27 | virtual ~LLVMException() throw() {} 28 | }; 29 | 30 | class ReverseTranslatorUknownOpcodeException : public Exception { 31 | private: 32 | ExtendedMCInst instruction; 33 | 34 | public: 35 | ReverseTranslatorUknownOpcodeException(ExtendedMCInst& instruction) 36 | : Exception("Encountered unknown upcode upon translation"), instruction(instruction) 37 | { 38 | } 39 | 40 | ExtendedMCInst& getInstruction() { 41 | return this->instruction; 42 | } 43 | virtual ~ReverseTranslatorUknownOpcodeException() throw() {} 44 | }; 45 | 46 | #endif /* _REVERSE_TRANSLATOR_EXCEPTIONS_H */ 47 | -------------------------------------------------------------------------------- /binary_translator/include/lldc/SystemInformation.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYSTEM_INFORMATION_H 2 | #define _SYSTEM_INFORMATION_H 3 | 4 | /** 5 | * This file contains classes for static information about the source system. 6 | * (i.e. information that needs to be set one time before the decompilation process, 7 | * and does not need to be changed afterwards) 8 | */ 9 | 10 | #include "llvm/IR/Type.h" 11 | #include "llvm/ADT/Twine.h" 12 | #include "llvm/IR/DerivedTypes.h" 13 | //#include "llvm/IR/Function.h" 14 | //#include "llvm/IR/Module.h" 15 | //#include "llvm/IR/LLVMContext.h" 16 | //#include "llvm/MC/MCDisassembler.h" 17 | //#include "llvm/Support/TargetRegistry.h" 18 | 19 | #include 20 | 21 | class ProcessorRegisterDescription 22 | { 23 | std::string name; 24 | llvm::Type* type; 25 | size_t index; 26 | unsigned regNum; 27 | public: 28 | ProcessorRegisterDescription(std::string name, llvm::Type* type, size_t index, unsigned regNum) : name(name), type(type), index(index), regNum(regNum) {} 29 | llvm::Twine getName() const {return llvm::Twine(name);} 30 | llvm::Type* getType() const {return type;} 31 | size_t getIndex() const {return index;} 32 | unsigned getRegNum() const {return regNum;} 33 | } ; 34 | 35 | class SystemInformation 36 | { 37 | private: 38 | std::list registerDescription; 39 | public: 40 | typedef std::list::iterator register_iterator; 41 | SystemInformation(std::list& regDesc) : registerDescription(regDesc) {} 42 | llvm::StructType* getProcessorStructTy() { 43 | std::vector elements; 44 | for (std::list::iterator itr = registerDescription.begin(); 45 | itr != registerDescription.end(); 46 | itr++) 47 | { 48 | elements.push_back(itr->getType()); 49 | } 50 | 51 | return llvm::StructType::create(elements, "processor_struct", true); 52 | } 53 | register_iterator register_description_begin() {return registerDescription.begin();} 54 | register_iterator register_description_end() {return registerDescription.end();} 55 | unsigned getGeneralRegisterBitWidth() {return 32;} 56 | }; 57 | 58 | #endif /* _SYSTEM_INFORMATION_H */ 59 | -------------------------------------------------------------------------------- /binary_translator/include/lldc/c_interface.h: -------------------------------------------------------------------------------- 1 | #ifndef _LLDC_C_INTERFACE_H 2 | #define _LLDC_C_INTERFACE_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif /* __cplusplus */ 9 | 10 | typedef struct 11 | { 12 | uint64_t address; 13 | uint64_t size; 14 | char *code; 15 | } GeneratedCode; 16 | 17 | typedef struct 18 | { 19 | const char * key; 20 | const char * value; 21 | } DictionaryElement; 22 | 23 | typedef struct 24 | { 25 | uint64_t start; 26 | uint64_t end; 27 | } ProgramCounterRange; 28 | 29 | typedef unsigned (*ReadCodeMemoryFunc)(void *opaque, uint64_t address, unsigned size, uint8_t *buffer); 30 | 31 | /** 32 | * Instrument the given code - wrap it in a function, so that it can be invoked with two parameters: 33 | * - The first parameter is the CPU state struct which contains all registers and flags. 34 | * - The second parameter is the instrumentation struct, which contains the handler functions for memory read and write. 35 | * @param architecture A string that describes the architecture. Is used as the constructor for the LLVM triple first part. 36 | * @param entry_point Entry point where code analysis is started. Has to lie in one of the ranges specified by pc_ranges. bien sur. 37 | * @param pc_ranges An array of ProgramCounterRange structs (the last one has to have start = end = 0). The code is 38 | * translated as long as the program counter of the current instruction falls in one of these ranges. If the program counter runs out of these 39 | * ranges, a function return is emitted and the current processor state is saved to the processor state struct (first argument). 40 | * @param generated_code_address The base address of the code that is generated. This is at the same time the function entry address of the 41 | * instrumented code. 42 | * @param get_code_callback This function is used to get data from code memory at compile time. 43 | * @param opaque Any pointer you want that is passed as first argument to the get_code_callback function. 44 | * @param generated_code The return structure where information about the generated code is stored. When size != 0 at return, you have to free 45 | * the code pointer after usage. 46 | * @param opts More options for more narrow LLVM processor selection. Currently not used. 47 | * @return 0 on success, error code otherwise. 48 | */ 49 | int instrument_memory_access(const char * architecture, 50 | uint64_t entry_point, 51 | ProgramCounterRange * pc_ranges, 52 | uint64_t generated_code_address, 53 | ReadCodeMemoryFunc get_code_callback, 54 | void *opaque, 55 | GeneratedCode * generated_code, 56 | DictionaryElement * opts); 57 | 58 | 59 | #ifdef __cplusplus 60 | } 61 | #endif /* __cplusplus */ 62 | 63 | #endif /* _LLDC_C_INTERFACE_H */ -------------------------------------------------------------------------------- /binary_translator/include/lldc/test_code.h: -------------------------------------------------------------------------------- 1 | #ifndef __TEST_CODE 2 | #define __TEST_CODE 3 | 4 | #include 5 | #include 6 | 7 | struct DataInMemory {uint64_t address; uint64_t length; const char * code;}; 8 | extern struct DataInMemory memory_data[]; 9 | extern uint64_t entry_point; 10 | extern size_t memory_data_entries; 11 | 12 | #endif /* __TEST_CODE */ 13 | -------------------------------------------------------------------------------- /binary_translator/include/lldc/util.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTIL_H 2 | #define _UTIL_H 3 | 4 | #include 5 | #include 6 | 7 | std::string intToHexString(uint64_t val); 8 | 9 | #endif /* _UTIL_H */ 10 | -------------------------------------------------------------------------------- /binary_translator/src/ArrayMemoryObject.cpp: -------------------------------------------------------------------------------- 1 | #include "lldc/ArrayMemoryObject.h" 2 | 3 | 4 | ArrayMemoryObject::ArrayMemoryObject(uint64_t base, size_t size) { 5 | this->data = new uint8_t[size]; 6 | this->size = size; 7 | this->base = base; 8 | } 9 | 10 | uint64_t ArrayMemoryObject::getBase() const 11 | { 12 | return this->base; 13 | } 14 | 15 | uint64_t ArrayMemoryObject::getExtent() const 16 | { 17 | return this->size; 18 | } 19 | 20 | int ArrayMemoryObject::readByte(uint64_t addr, uint8_t * byte) const 21 | { 22 | uint64_t offset = addr - this->base; 23 | if (offset > this->size) 24 | return -1; 25 | *byte = this->data[offset]; 26 | return 0; 27 | } 28 | 29 | ArrayMemoryObject::~ArrayMemoryObject() 30 | { 31 | if (this->data) delete[] this->data; 32 | } 33 | 34 | uint8_t * ArrayMemoryObject::getArray() 35 | { 36 | return this->data; 37 | } -------------------------------------------------------------------------------- /binary_translator/src/BasicBlockCache.cpp: -------------------------------------------------------------------------------- 1 | #include "lldc/BasicBlockCache.h" 2 | #include 3 | #include "lldc/PathState.h" 4 | #include "lldc/util.h" 5 | 6 | #include "llvm/Support/raw_ostream.h" 7 | 8 | using namespace llvm; 9 | 10 | BasicBlockCache::BasicBlockCache(LLVMContext& context) 11 | : context(context) 12 | { 13 | } 14 | 15 | void BasicBlockCache::insert(PathState* state, uint64_t start_pc, uint64_t end_pc, BasicBlock * bb) { 16 | outs() << "Inserting basic block " << intToHexString(start_pc) << " into cache" << '\n'; 17 | PcToBBMap& pcToBBMap = this->basicBlockCache[state->getFunction()]; 18 | assert(pcToBBMap.find(start_pc) == pcToBBMap.end()); 19 | pcToBBMap.insert(std::make_pair(start_pc, TranslatedBasicBlock(bb, start_pc, end_pc))); 20 | } 21 | 22 | TranslatedBasicBlock* BasicBlockCache::find(PathState* state, uint64_t pc) { 23 | return this->find(state->getFunction(), pc); 24 | } 25 | 26 | TranslatedBasicBlock* BasicBlockCache::find(llvm::Function* function, uint64_t pc) { 27 | BasicBlockCacheMap::iterator itr_outer = this->basicBlockCache.find(function); 28 | if (itr_outer != this->basicBlockCache.end()) 29 | { 30 | PcToBBMap& pcToBBMap = itr_outer->second; 31 | PcToBBMap::iterator itr_inner = pcToBBMap.find(pc); 32 | if (itr_inner != pcToBBMap.end()) 33 | return &itr_inner->second; 34 | else 35 | return NULL; 36 | } 37 | else 38 | return NULL; 39 | } 40 | 41 | 42 | 43 | void BasicBlockCache::invalidateBasicBlocks(uint64_t pc) { 44 | /* TODO */ 45 | } 46 | -------------------------------------------------------------------------------- /binary_translator/src/FunctionCache.cpp: -------------------------------------------------------------------------------- 1 | #include "lldc/FunctionCache.h" 2 | #include "lldc/ReverseTranslationConfiguration.h" 3 | #include "lldc/util.h" 4 | #include "lldc/PathState.h" 5 | #include "lldc/PathsManager.h" 6 | 7 | using namespace llvm; 8 | 9 | //TODO: Remove this include and put registers to pass in the configuration 10 | #define GET_REGINFO_ENUM 11 | #define GET_INSTRINFO_ENUM 12 | #include "ARMBaseInfo.h" 13 | 14 | 15 | void FunctionCache::insertFunction(uint64_t pc, Function* function) { 16 | this->cache.insert(std::make_pair(pc, function)); 17 | } 18 | 19 | Function* FunctionCache::getOrCreateFunction(ReverseTranslationConfiguration* config, Module* module, uint64_t function_address) 20 | { 21 | std::map::const_iterator itr = this->cache.find(function_address); 22 | 23 | if (itr != this->cache.end()) 24 | return itr->second; 25 | 26 | Function* func = cast(module->getOrInsertFunction(intToHexString(function_address), 27 | (Type *) Type::getInt32Ty(config->getLLVMContext()), 28 | Type::getInt32Ty(config->getLLVMContext()) /* R0 */, 29 | Type::getInt32Ty(config->getLLVMContext()) /* R1 */, 30 | Type::getInt32Ty(config->getLLVMContext()) /* R2 */, 31 | Type::getInt32Ty(config->getLLVMContext()) /* R3 */, 32 | Type::getInt32Ty(config->getLLVMContext()) /* R4 */, 33 | Type::getInt32Ty(config->getLLVMContext()) /* R5 */, 34 | Type::getInt32Ty(config->getLLVMContext()) /* R6 */, 35 | Type::getInt32Ty(config->getLLVMContext()) /* R7 */, 36 | Type::getInt32Ty(config->getLLVMContext()) /* R8 */, 37 | Type::getInt32Ty(config->getLLVMContext()) /* R9 */, 38 | Type::getInt32Ty(config->getLLVMContext()) /* R10 */, 39 | Type::getInt32Ty(config->getLLVMContext()) /* R11 */, 40 | Type::getInt32Ty(config->getLLVMContext()) /* R12 */, 41 | Type::getInt32Ty(config->getLLVMContext()) /* SP */, 42 | Type::getInt32Ty(config->getLLVMContext()) /* LR */, 43 | /* TODO: Processor mode should be passed */ 44 | NULL)); 45 | 46 | Function::arg_iterator args = func->arg_begin(); 47 | 48 | std::map values; 49 | 50 | args->setName("R0"); values.insert(std::make_pair(ARM::R0, args)); 51 | args++; args->setName("R1"); values.insert(std::make_pair(ARM::R1, args)); 52 | args++; args->setName("R2"); values.insert(std::make_pair(ARM::R2, args)); 53 | args++; args->setName("R3"); values.insert(std::make_pair(ARM::R3, args)); 54 | args++; args->setName("R4"); values.insert(std::make_pair(ARM::R4, args)); 55 | args++; args->setName("R5"); values.insert(std::make_pair(ARM::R5, args)); 56 | args++; args->setName("R6"); values.insert(std::make_pair(ARM::R6, args)); 57 | args++; args->setName("R7"); values.insert(std::make_pair(ARM::R7, args)); 58 | args++; args->setName("R8"); values.insert(std::make_pair(ARM::R8, args)); 59 | args++; args->setName("R9"); values.insert(std::make_pair(ARM::R9, args)); 60 | args++; args->setName("R10"); values.insert(std::make_pair(ARM::R10, args)); 61 | args++; args->setName("R11"); values.insert(std::make_pair(ARM::R11, args)); 62 | args++; args->setName("R12"); values.insert(std::make_pair(ARM::R12, args)); 63 | args++; args->setName("SP"); values.insert(std::make_pair(ARM::SP, args)); 64 | args++; args->setName("LR"); values.insert(std::make_pair(ARM::LR, args)); 65 | 66 | config->getBasicBlockTranslationStateManager()-> 67 | createPath(config->getLLVMContext(), 68 | module, 69 | func, 70 | function_address, 71 | values); 72 | this->cache.insert(std::make_pair(function_address, func)); 73 | return func; 74 | } 75 | 76 | -------------------------------------------------------------------------------- /binary_translator/src/InstructionTranslationUnitCache.cpp: -------------------------------------------------------------------------------- 1 | #include "lldc/InstructionTranslationUnitCache.h" 2 | #include "lldc/util.h" 3 | 4 | #include "llvm/IR/IRBuilder.h" 5 | #include "llvm/IR/BasicBlock.h" 6 | #include "llvm/IR/Function.h" 7 | #include "llvm/IR/Value.h" 8 | 9 | using namespace llvm; 10 | 11 | 12 | void InstructionTranslationUnit::addIncoming(const std::map< unsigned, llvm::Value* >& values, llvm::BasicBlock* predecessor) 13 | { 14 | for (std::map< unsigned, Value* >::const_iterator itr = values.begin(); 15 | itr != values.end(); 16 | itr++) 17 | { 18 | assert(phi_nodes.find(itr->first) != phi_nodes.end() && "Found value that is not specified in the value information of the configuration"); 19 | 20 | phi_nodes[itr->first]->addIncoming(itr->second, predecessor); 21 | } 22 | } 23 | 24 | 25 | bool UnfinishedInstructionTranslationUnit::operator==(const UnfinishedInstructionTranslationUnit& other) 26 | { 27 | return instruction_translation_unit.getProgramCounter() == other.instruction_translation_unit.getProgramCounter(); 28 | } 29 | 30 | InstructionTranslationUnit* InstructionTranslationUnitCache::find(Function* function, uint64_t pc) 31 | { 32 | std::map< Function*, std::map< uint64_t, InstructionTranslationUnit > >::iterator outer_itr = instruction_translation_unit_cache.find(function); 33 | if (outer_itr != instruction_translation_unit_cache.end()) 34 | { 35 | std::map< uint64_t, InstructionTranslationUnit >::iterator inner_itr = outer_itr->second.find(pc); 36 | if (inner_itr != outer_itr->second.end()) 37 | return &inner_itr->second; 38 | } 39 | 40 | return NULL; 41 | } 42 | 43 | InstructionTranslationUnit* InstructionTranslationUnitCache::create( 44 | ReverseTranslationConfiguration& config, 45 | Function* function, 46 | uint64_t pc) 47 | { 48 | BasicBlock *head_bb = BasicBlock::Create(config.getLLVMContext(), intToHexString(pc), function); 49 | IRBuilder<> builder(head_bb); 50 | InstructionTranslationUnit& unit = instruction_translation_unit_cache[function][pc]; 51 | std::map< unsigned, Value* > new_values; 52 | 53 | unit.head_bb = head_bb; 54 | unit.instruction_set = 0; 55 | unit.original_instruction = 0; 56 | unit.is_finished = false; 57 | unit.function = function; 58 | unit.pc = pc; 59 | 60 | for (std::list< ValueInformation >::const_iterator value_info_itr = config.getValueInformation().begin(); 61 | value_info_itr != config.getValueInformation().end(); 62 | value_info_itr++) 63 | { 64 | PHINode *phi = builder.CreatePHI(value_info_itr->getType(), 0, value_info_itr->getName()); 65 | unit.phi_nodes[value_info_itr->getId()] = phi; 66 | new_values[value_info_itr->getId()] = phi; 67 | } 68 | 69 | 70 | this->unfinished_instruction_translation_units.push_back(new UnfinishedInstructionTranslationUnit(unit, new_values)); 71 | 72 | return &unit; 73 | } 74 | 75 | bool InstructionTranslationUnitCache::has_more_unfinished_translation_units() 76 | { 77 | return !this->unfinished_instruction_translation_units.empty(); 78 | } 79 | 80 | UnfinishedInstructionTranslationUnit* InstructionTranslationUnitCache::get_next_unfinished_translation_unit() 81 | { 82 | UnfinishedInstructionTranslationUnit* unit = this->unfinished_instruction_translation_units.front(); 83 | this->unfinished_instruction_translation_units.pop_front(); 84 | return unit; 85 | } 86 | 87 | UnfinishedInstructionTranslationUnit::UnfinishedInstructionTranslationUnit(InstructionTranslationUnit& unit, const std::map< unsigned, llvm::Value* >& values) 88 | : instruction_translation_unit(unit), values(values) 89 | { 90 | } 91 | 92 | /** 93 | * Get a translated instruction, if it is already translated, or create a new one 94 | * if no translation has been found. 95 | */ 96 | InstructionTranslationUnit* InstructionTranslationUnitCache::find_create( 97 | ReverseTranslationConfiguration& config, 98 | Function* function, 99 | uint64_t pc, 100 | const std::map< unsigned, Value* >& predecessor_values, 101 | BasicBlock *predecessor_bb, 102 | bool terminate_last_block) 103 | { 104 | InstructionTranslationUnit* unit = this->find(function, pc); 105 | 106 | if (!unit) 107 | { 108 | unit = this->create(config, function, pc); 109 | } 110 | 111 | unit->addIncoming(predecessor_values, predecessor_bb); 112 | 113 | if (terminate_last_block) 114 | { 115 | IRBuilder<> builder(predecessor_bb); 116 | 117 | builder.CreateBr(unit->getHead()); 118 | } 119 | 120 | return unit; 121 | } 122 | 123 | InstructionTranslationUnitCache& InstructionTranslationUnitCache::getInstance() 124 | { 125 | static InstructionTranslationUnitCache instance; 126 | 127 | return instance; 128 | } -------------------------------------------------------------------------------- /binary_translator/src/InstrumentMemoryAccessPass.cpp: -------------------------------------------------------------------------------- 1 | #include "lldc/InstrumentMemoryAccessPass.h" 2 | #include "llvm/IR/Instructions.h" 3 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 4 | 5 | using namespace llvm; 6 | 7 | InstrumentMemoryAccessPass::InstrumentMemoryAccessPass(char& pid, Value* read_handler, Value* write_handler) 8 | : BasicBlockPass(pid), read_handler(read_handler), write_handler(write_handler) 9 | { 10 | } 11 | 12 | 13 | bool InstrumentMemoryAccessPass::doInitialization(Function &F) 14 | { 15 | return false; 16 | } 17 | 18 | bool InstrumentMemoryAccessPass::runOnBasicBlock(BasicBlock &bb) 19 | { 20 | for (BasicBlock::iterator itr = bb.begin(); 21 | itr != bb.end(); 22 | itr++) 23 | { 24 | //Only do instructions that have been marked as translated, otherwise the pre/post-amble is also translated 25 | if (!itr->getMetadata("translated_memory_access")) 26 | continue; 27 | 28 | if (itr->getOpcode() == Instruction::Load) 29 | { 30 | Value* address = cast(*itr).getPointerOperand(); 31 | uint32_t size = 0; 32 | 33 | if (address->getType()->isPointerTy() && address->getType()->getPointerElementType()->isIntegerTy()) 34 | { 35 | switch(cast(address->getType()->getPointerElementType())->getBitWidth()) 36 | { 37 | case 8: 38 | size = 1; 39 | break; 40 | case 16: 41 | size = 2; 42 | break; 43 | case 32: 44 | size = 4; 45 | break; 46 | default: 47 | assert(false && "Unknown integer type size"); 48 | } 49 | } 50 | else 51 | { 52 | assert(false && "Unknown type as argument to LoadInst"); 53 | } 54 | 55 | SmallVector args; 56 | Value* castAddress = CastInst::CreatePointerCast(address, Type::getInt8PtrTy(bb.getContext()), "load_addr.", itr); 57 | args.push_back(castAddress); 58 | args.push_back(ConstantInt::get(Type::getInt32Ty(bb.getContext()), size)); 59 | Value* value = CallInst::Create(read_handler, args, "handle_read.", itr); 60 | ReplaceInstWithInst(bb.getInstList(), itr, CastInst::CreateIntegerCast(value, itr->getType(), false)); 61 | } 62 | else if (itr->getOpcode() == Instruction::Store) 63 | { 64 | Value* address = cast(*itr).getPointerOperand(); 65 | Value* value = cast(*itr).getValueOperand(); 66 | uint32_t size = 0; 67 | 68 | if (address->getType()->isPointerTy() && address->getType()->getPointerElementType()->isIntegerTy()) 69 | { 70 | switch(cast(address->getType()->getPointerElementType())->getBitWidth()) 71 | { 72 | case 8: 73 | size = 1; 74 | break; 75 | case 16: 76 | size = 2; 77 | break; 78 | case 32: 79 | size = 4; 80 | break; 81 | default: 82 | assert(false && "Unknown integer type size"); 83 | } 84 | } 85 | else 86 | { 87 | assert(false && "Unknown type as argument to LoadInst"); 88 | } 89 | 90 | SmallVector args; 91 | Value* castAddress = CastInst::CreatePointerCast(address, Type::getInt8PtrTy(bb.getContext()), "store_addr.", itr); 92 | Value* castValue = CastInst::CreateIntegerCast(value, Type::getInt32Ty(bb.getContext()), false, "store_val.", itr); 93 | args.push_back(castAddress); 94 | args.push_back(ConstantInt::get(Type::getInt32Ty(bb.getContext()), size)); 95 | args.push_back(castValue); 96 | ReplaceInstWithInst(bb.getInstList(), itr, CallInst::Create(write_handler, args)); 97 | } 98 | } 99 | 100 | return false; 101 | } 102 | 103 | bool InstrumentMemoryAccessPass::doFinalization(Function &F) 104 | { 105 | return false; 106 | } 107 | 108 | void InstrumentMemoryAccessPass::getAnalysisUsage(AnalysisUsage &info) const 109 | { 110 | info.setPreservesCFG(); 111 | } 112 | 113 | const char * InstrumentMemoryAccessPass::getPassName() const 114 | { 115 | return "Instrument Memory Access"; 116 | } -------------------------------------------------------------------------------- /binary_translator/src/PathState.cpp: -------------------------------------------------------------------------------- 1 | #include "lldc/PathState.h" 2 | #include "lldc/BasicBlockCache.h" 3 | #include "lldc/ReverseTranslationConfiguration.h" 4 | #include "lldc/PathsManager.h" 5 | 6 | #include "llvm/Support/raw_ostream.h" 7 | 8 | #include 9 | 10 | using namespace llvm; 11 | 12 | 13 | /** 14 | * This class encapsules the translation state of a single basic block. 15 | * It only exists while a basic block has not yet been completely translated, 16 | * afterwards the basic block information is managed by the basic block cache. 17 | */ 18 | PathState::PathState(llvm::BasicBlock* bb, llvm::Module* mod) 19 | : mod(mod), start_pc(-1), pc(-1), thumb(true) 20 | { 21 | bbs.push_back(bb); 22 | } 23 | 24 | PathState::PathState() 25 | : thumb(true) 26 | { 27 | } 28 | 29 | void PathState::init(llvm::BasicBlock* bb, 30 | llvm::Module* mod, 31 | uint64_t start_pc, 32 | std::map& values, 33 | bool thumb) { 34 | this->bbs.erase(this->bbs.begin(), this->bbs.end()); 35 | this->bbs.push_back(bb); 36 | this->mod = mod; 37 | this->pc = start_pc; 38 | this->values = values; 39 | this->thumb = thumb; 40 | 41 | outs() << "Called init on state " << intToHexString(reinterpret_cast(this)) << ": (thumb = " << (this->thumb ? "true" : "false") << ")" << '\n'; 42 | } 43 | 44 | llvm::LLVMContext& PathState::getContext() { 45 | return this->bbs.back()->getContext(); 46 | } 47 | 48 | llvm::BasicBlock* PathState::getBasicBlock() { 49 | return this->bbs.back(); 50 | } 51 | 52 | llvm::Module* PathState::getModule() { 53 | return this->mod; 54 | } 55 | 56 | llvm::Function* PathState::getFunction() { 57 | return this->bbs.back()->getParent(); 58 | } 59 | 60 | void PathState::setProgramCounter(uint64_t pc) { 61 | this->pc = pc; 62 | } 63 | 64 | uint64_t PathState::getProgramCounter() { 65 | return this->pc; 66 | } 67 | 68 | void PathState::setRegister(unsigned idx, llvm::Value* val) { 69 | this->values[idx] = val; 70 | } 71 | 72 | llvm::Value* PathState::getRegister(unsigned idx) { 73 | return this->values[idx]; 74 | } 75 | 76 | void PathState::setCondition(unsigned idx, llvm::Value* val) { 77 | this->values[idx] = val; 78 | } 79 | 80 | llvm::Value* PathState::getCondition(unsigned idx) { 81 | return this->values[idx]; 82 | } 83 | 84 | void PathState::instructionFinished(ReverseTranslationConfiguration* config, uint64_t next_pc) { 85 | llvm::BasicBlock* bb = llvm::BasicBlock::Create(this->getContext(), intToHexString(next_pc), this->getFunction()); 86 | llvm::IRBuilder<> builder(this->getBasicBlock()); 87 | builder.CreateBr(bb); 88 | config->getBasicBlockTranslationStateManager()->getBasicBlockCache()->insert(this, this->pc, next_pc, this->bbs.back()); 89 | this->bbs.push_back(bb); 90 | this->pc = next_pc; 91 | } 92 | 93 | 94 | /** 95 | * Call this in the very end when the basic block is finished and all it successor 96 | * translation states have been generated to do some cleanup. 97 | */ 98 | void PathState::translationFinished(ReverseTranslationConfiguration* config, uint64_t end_pc) { 99 | // config->getBasicBlockTranslationStateManager()->getBasicBlockCache()->insert(this, start_pc, end_pc, this->bbs.back()); 100 | //TODO: Destroy state 101 | config->getBasicBlockTranslationStateManager()->getBasicBlockCache()->insert(this, this->pc, end_pc, this->bbs.back()); 102 | config->getBasicBlockTranslationStateManager()->destroyPath(this); 103 | } 104 | 105 | bool PathState::isTranslationFinished() { 106 | return false; 107 | } 108 | 109 | PathState::~PathState() { 110 | } 111 | 112 | void PathState::setThumb(bool val) { 113 | // outs() << "Setting thumb mode of state " << intToHexString(reinterpret_cast(this)) << " to " << (val ? "true" : "false") << '\n'; 114 | this->thumb = val; 115 | } 116 | 117 | bool PathState::isThumb() { 118 | // outs() << "Getting thumb mode of state " << intToHexString(reinterpret_cast(this)) << ": " << (this->thumb ? "true" : "false") << '\n'; 119 | return this->thumb; 120 | } 121 | 122 | 123 | -------------------------------------------------------------------------------- /binary_translator/src/PathsManager.cpp: -------------------------------------------------------------------------------- 1 | #include "llvm/Support/raw_ostream.h" 2 | 3 | #include "lldc/PathsManager.h" 4 | 5 | using namespace llvm; 6 | using std::list; 7 | using std::find; 8 | 9 | PathsManager::PathsManager(BasicBlockCache* cache) 10 | : cache(cache) 11 | { 12 | } 13 | 14 | PathState* PathsManager::createPath(PathState* previous, uint64_t pc) { 15 | return createPath(previous->getContext(), 16 | previous->getModule(), 17 | previous->getFunction(), 18 | pc, 19 | previous->values); 20 | } 21 | 22 | PathState* PathsManager::createPath(PathState* previous, 23 | llvm::Function* func, 24 | uint64_t start_pc) 25 | { 26 | return createPath(previous->getContext(), 27 | previous->getModule(), 28 | func, 29 | start_pc, 30 | previous->values); 31 | } 32 | 33 | PathState* PathsManager::createPath(llvm::LLVMContext& context, 34 | llvm::Module* mod, 35 | llvm::Function* func, 36 | uint64_t start_pc, 37 | std::map& values) 38 | { 39 | outs() << "Creating new path " << intToHexString(start_pc) << " for function " << intToHexString(reinterpret_cast(func)) << '\n'; 40 | llvm::BasicBlock* bb = llvm::BasicBlock::Create(context, intToHexString(start_pc), func); 41 | PathState* state; 42 | if (freeStates.size() > 0) { 43 | state = freeStates.back(); 44 | freeStates.pop_back(); 45 | } else { 46 | state = new PathState(); 47 | } 48 | 49 | usedStates.push_back(state); 50 | 51 | state->init(bb, mod, start_pc, values); 52 | 53 | return state; 54 | } 55 | 56 | ReverseTranslateBasicBlock* PathsManager::getOrCreateReverseTranslateBasicBlock(PathState* previous, uint64_t pc) { 57 | outs() << "Getting or creating new path from path " << intToHexString(reinterpret_cast(previous)) << " at " << intToHexString(pc) << '\n'; 58 | ReverseTranslateBasicBlock* bb = this->getReverseTranslateBasicBlock(previous->getFunction(), pc); 59 | if (bb) 60 | return bb; 61 | 62 | return createPath(previous, pc); 63 | } 64 | 65 | ReverseTranslateBasicBlock* PathsManager::getReverseTranslateBasicBlock(llvm::Function* function, uint64_t pc) { 66 | TranslatedBasicBlock* bb = this->cache->find(function, pc); 67 | 68 | if (bb) 69 | return bb; 70 | 71 | for (list::const_iterator itr = this->usedStates.begin(); 72 | itr != this->usedStates.end(); 73 | itr++) 74 | { 75 | if ((*itr)->getProgramCounter() == pc) { 76 | assert((*itr)->getFunction() == function && "Function different for searched block and found block"); 77 | return *itr; 78 | } 79 | } 80 | 81 | return 0; 82 | } 83 | 84 | void PathsManager::destroyPath(PathState* state) { 85 | outs() << "Destroying state " << intToHexString(reinterpret_cast(state)) << " at pc " << intToHexString(state->getProgramCounter()) << '\n'; 86 | list::iterator itr = find(this->usedStates.begin(), this->usedStates.end(), state); 87 | if (itr != this->usedStates.end()) { 88 | this->usedStates.erase(itr); 89 | this->freeStates.push_back(state); 90 | } 91 | else { 92 | //TODO: Error, state not found 93 | assert(false && "State to destroy not in used states list"); 94 | } 95 | } 96 | 97 | PathState* PathsManager::getUnfinishedPath() { 98 | if (this->usedStates.empty()) { 99 | outs() << "No more unfinished states" << '\n'; 100 | return 0; 101 | } 102 | 103 | PathState* state = this->usedStates.front(); 104 | outs() << "Getting unfinished state " << intToHexString(reinterpret_cast(state)) << '\n'; 105 | return state; 106 | } -------------------------------------------------------------------------------- /binary_translator/src/ProxyMemoryObject.cpp: -------------------------------------------------------------------------------- 1 | #include "lldc/ProxyMemoryObject.h" 2 | 3 | 4 | ProxyMemoryObject::ProxyMemoryObject(ReadCodeMemoryFunc read_func, void * opaque, uint64_t base, size_t size) 5 | : opaque(opaque), 6 | read_func(read_func), 7 | size(size), 8 | base(base) 9 | { 10 | } 11 | 12 | uint64_t ProxyMemoryObject::getBase() const 13 | { 14 | return this->base; 15 | } 16 | 17 | uint64_t ProxyMemoryObject::getExtent() const 18 | { 19 | return this->size; 20 | } 21 | 22 | int ProxyMemoryObject::readByte(uint64_t addr, uint8_t * byte) const 23 | { 24 | if (this->read_func(this->opaque, addr, 1, byte) == 1) 25 | return 0; 26 | else 27 | return -1; 28 | } 29 | 30 | int ProxyMemoryObject::readBytes(uint64_t addr, uint64_t size, uint8_t * byte) const 31 | { 32 | if (this->read_func(this->opaque, addr, size, byte) == size) 33 | return 0; 34 | else 35 | return -1; 36 | } 37 | 38 | ProxyMemoryObject::~ProxyMemoryObject() 39 | { 40 | } -------------------------------------------------------------------------------- /binary_translator/src/RecordingMemoryManager.cpp: -------------------------------------------------------------------------------- 1 | //===- RecordingMemoryManager.cpp - Recording memory manager --------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This memory manager allocates local storage and keeps a record of each 11 | // allocation. Iterators are provided for all data and code allocations. 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #include "lldc/RecordingMemoryManager.h" 16 | using namespace llvm; 17 | 18 | RecordingMemoryManager::~RecordingMemoryManager() { 19 | for (SmallVectorImpl::iterator 20 | I = AllocatedCodeMem.begin(), E = AllocatedCodeMem.end(); 21 | I != E; ++I) 22 | sys::Memory::releaseMappedMemory(I->first); 23 | for (SmallVectorImpl::iterator 24 | I = AllocatedDataMem.begin(), E = AllocatedDataMem.end(); 25 | I != E; ++I) 26 | sys::Memory::releaseMappedMemory(I->first); 27 | } 28 | 29 | uint8_t *RecordingMemoryManager:: 30 | allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) { 31 | // The recording memory manager is just a local copy of the remote target. 32 | // The alignment requirement is just stored here for later use. Regular 33 | // heap storage is sufficient here, but we're using mapped memory to work 34 | // around a bug in MCJIT. 35 | sys::MemoryBlock Block = allocateSection(Size); 36 | AllocatedCodeMem.push_back(Allocation(Block, Alignment)); 37 | return (uint8_t*)Block.base(); 38 | } 39 | 40 | uint8_t *RecordingMemoryManager:: 41 | allocateDataSection(uintptr_t Size, unsigned Alignment, 42 | unsigned SectionID, bool IsReadOnly) { 43 | // The recording memory manager is just a local copy of the remote target. 44 | // The alignment requirement is just stored here for later use. Regular 45 | // heap storage is sufficient here, but we're using mapped memory to work 46 | // around a bug in MCJIT. 47 | sys::MemoryBlock Block = allocateSection(Size); 48 | AllocatedDataMem.push_back(Allocation(Block, Alignment)); 49 | return (uint8_t*)Block.base(); 50 | } 51 | 52 | sys::MemoryBlock RecordingMemoryManager::allocateSection(uintptr_t Size) { 53 | error_code ec; 54 | sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(Size, 55 | &Near, 56 | sys::Memory::MF_READ | 57 | sys::Memory::MF_WRITE, 58 | ec); 59 | assert(!ec && MB.base()); 60 | 61 | // FIXME: This is part of a work around to keep sections near one another 62 | // when MCJIT performs relocations after code emission but before 63 | // the generated code is moved to the remote target. 64 | // Save this address as the basis for our next request 65 | Near = MB; 66 | return MB; 67 | } 68 | 69 | void RecordingMemoryManager::setMemoryWritable() { llvm_unreachable("Unexpected!"); } 70 | void RecordingMemoryManager::setMemoryExecutable() { llvm_unreachable("Unexpected!"); } 71 | void RecordingMemoryManager::setPoisonMemory(bool poison) { llvm_unreachable("Unexpected!"); } 72 | void RecordingMemoryManager::AllocateGOT() { llvm_unreachable("Unexpected!"); } 73 | uint8_t *RecordingMemoryManager::getGOTBase() const { 74 | llvm_unreachable("Unexpected!"); 75 | return 0; 76 | } 77 | uint8_t *RecordingMemoryManager::startFunctionBody(const Function *F, uintptr_t &ActualSize){ 78 | llvm_unreachable("Unexpected!"); 79 | return 0; 80 | } 81 | uint8_t *RecordingMemoryManager::allocateStub(const GlobalValue* F, unsigned StubSize, 82 | unsigned Alignment) { 83 | llvm_unreachable("Unexpected!"); 84 | return 0; 85 | } 86 | void RecordingMemoryManager::endFunctionBody(const Function *F, uint8_t *FunctionStart, 87 | uint8_t *FunctionEnd) { 88 | llvm_unreachable("Unexpected!"); 89 | } 90 | uint8_t *RecordingMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) { 91 | llvm_unreachable("Unexpected!"); 92 | return 0; 93 | } 94 | uint8_t *RecordingMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) { 95 | llvm_unreachable("Unexpected!"); 96 | return 0; 97 | } 98 | void RecordingMemoryManager::deallocateFunctionBody(void *Body) { 99 | llvm_unreachable("Unexpected!"); 100 | } 101 | 102 | bool RecordingMemoryManager::applyPermissions(std::string*) { 103 | llvm_unreachable("Unexpected!"); 104 | } 105 | 106 | static int jit_noop() { 107 | return 0; 108 | } 109 | 110 | void *RecordingMemoryManager::getPointerToNamedFunction(const std::string &Name, 111 | bool AbortOnFailure) { 112 | // We should not invoke parent's ctors/dtors from generated main()! 113 | // On Mingw and Cygwin, the symbol __main is resolved to 114 | // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors 115 | // (and register wrong callee's dtors with atexit(3)). 116 | // We expect ExecutionEngine::runStaticConstructorsDestructors() 117 | // is called before ExecutionEngine::runFunctionAsMain() is called. 118 | if (Name == "__main") return (void*)(intptr_t)&jit_noop; 119 | 120 | return NULL; 121 | } 122 | -------------------------------------------------------------------------------- /binary_translator/src/ReverseTranslationConfiguration.cpp: -------------------------------------------------------------------------------- 1 | #include "lldc/ReverseTranslationConfiguration.h" 2 | #include "lldc/PathState.h" 3 | #include "lldc/LLVMArmRegisters.h" 4 | 5 | #include "llvm/Support/raw_ostream.h" 6 | 7 | using namespace llvm; 8 | 9 | ReverseTranslationConfiguration::ReverseTranslationConfiguration( 10 | llvm::LLVMContext& llvmContext, 11 | const llvm::MCDisassembler* thumbDisassembler, 12 | const llvm::MCDisassembler* armDisassembler, 13 | const llvm::Target* target, 14 | llvm::StructType* instrumentation_struct_ty, 15 | SystemInformation* sys_info, 16 | PathsManager* mgr) 17 | : llvmContext(llvmContext), 18 | thumbDisassembler(thumbDisassembler), 19 | armDisassembler(armDisassembler), target(target), 20 | instrumentation_struct_ty(instrumentation_struct_ty), 21 | sys_info(sys_info), 22 | basicBlockTranslationStateManager(mgr) 23 | { 24 | } 25 | 26 | const llvm::MCDisassembler* ReverseTranslationConfiguration::getDisassembler(unsigned instruction_set) { 27 | assert(instruction_set == 0); 28 | 29 | return this->thumbDisassembler; 30 | } 31 | 32 | llvm::LLVMContext& ReverseTranslationConfiguration::getLLVMContext() { 33 | return this->llvmContext; 34 | } 35 | 36 | const llvm::Target* ReverseTranslationConfiguration::getTarget(PathState* state) { 37 | return this->target; 38 | } 39 | 40 | SystemInformation* ReverseTranslationConfiguration::getSystemInformation() { 41 | return this->sys_info; 42 | } 43 | 44 | llvm::StructType* ReverseTranslationConfiguration::getInstrumentationStructTy() { 45 | return this->instrumentation_struct_ty; 46 | } 47 | 48 | ReverseInstructionTranslatorFunction ReverseTranslationConfiguration::getReverseInstructionTranslator(ExtendedMCInst& instruction) { 49 | std::map::const_iterator itr = this->instruction_translators.find(instruction.getOpcode()); 50 | 51 | if (itr == this->instruction_translators.end()) 52 | throw ReverseTranslatorUknownOpcodeException(instruction); 53 | 54 | return itr->second; 55 | } 56 | 57 | std::map& ReverseTranslationConfiguration::getInstructionTranslators() { 58 | return this->instruction_translators; 59 | } 60 | 61 | PathsManager* ReverseTranslationConfiguration::getBasicBlockTranslationStateManager() { 62 | return basicBlockTranslationStateManager; 63 | } 64 | 65 | FunctionCache& ReverseTranslationConfiguration::getFunctionCache() { 66 | return functionCache; 67 | } 68 | 69 | const std::list& ReverseTranslationConfiguration::getValueInformation() 70 | { 71 | static const ValueInformation static_value_info[] = { 72 | ValueInformation("r0.", ARM::R0, Type::getInt32Ty(this->getLLVMContext())), 73 | ValueInformation("r1.", ARM::R1, Type::getInt32Ty(this->getLLVMContext())), 74 | ValueInformation("r2.", ARM::R2, Type::getInt32Ty(this->getLLVMContext())), 75 | ValueInformation("r3.", ARM::R3, Type::getInt32Ty(this->getLLVMContext())), 76 | ValueInformation("r4.", ARM::R4, Type::getInt32Ty(this->getLLVMContext())), 77 | ValueInformation("r5.", ARM::R5, Type::getInt32Ty(this->getLLVMContext())), 78 | ValueInformation("r6.", ARM::R6, Type::getInt32Ty(this->getLLVMContext())), 79 | ValueInformation("r7.", ARM::R7, Type::getInt32Ty(this->getLLVMContext())), 80 | ValueInformation("r8.", ARM::R8, Type::getInt32Ty(this->getLLVMContext())), 81 | ValueInformation("r9.", ARM::R9, Type::getInt32Ty(this->getLLVMContext())), 82 | ValueInformation("r10.", ARM::R10, Type::getInt32Ty(this->getLLVMContext())), 83 | ValueInformation("r11.", ARM::R11, Type::getInt32Ty(this->getLLVMContext())), 84 | ValueInformation("r12.", ARM::R12, Type::getInt32Ty(this->getLLVMContext())), 85 | ValueInformation("sp.", ARM::SP, Type::getInt32Ty(this->getLLVMContext())), 86 | ValueInformation("lr.", ARM::LR, Type::getInt32Ty(this->getLLVMContext())), 87 | ValueInformation("cpsr.", ARM::CPSR, Type::getInt32Ty(this->getLLVMContext())), 88 | ValueInformation("flag_z.", ARM::FLAG_Z, Type::getInt1Ty(this->getLLVMContext())), 89 | ValueInformation("flag_n.", ARM::FLAG_N, Type::getInt1Ty(this->getLLVMContext())), 90 | ValueInformation("flag_c.", ARM::FLAG_C, Type::getInt1Ty(this->getLLVMContext())), 91 | ValueInformation("flag_v.", ARM::FLAG_V, Type::getInt1Ty(this->getLLVMContext()))}; 92 | 93 | //TODO: This is still ARM specific, make it configurable 94 | static std::list< ValueInformation > value_information(static_value_info, static_value_info + (sizeof(static_value_info) / sizeof(ValueInformation))); 95 | 96 | return value_information; 97 | } 98 | -------------------------------------------------------------------------------- /binary_translator/src/c_interface.cpp: -------------------------------------------------------------------------------- 1 | #include "lldc/c_interface.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "llvm/Support/TargetRegistry.h" 10 | #include "llvm/Support/TargetSelect.h" 11 | #include "llvm/ADT/OwningPtr.h" 12 | #include "llvm/MC/MCAsmBackend.h" 13 | #include "llvm/MC/MCAsmInfo.h" 14 | #include "llvm/MC/MCContext.h" 15 | #include "llvm/MC/MCInstPrinter.h" 16 | #include "llvm/MC/MCInstrInfo.h" 17 | #include "llvm/MC/MCObjectFileInfo.h" 18 | #include "llvm/MC/MCParser/AsmLexer.h" 19 | #include "llvm/MC/MCRegisterInfo.h" 20 | #include "llvm/MC/MCSectionMachO.h" 21 | #include "llvm/MC/MCStreamer.h" 22 | #include "llvm/MC/MCDisassembler.h" 23 | #include "llvm/MC/MCSubtargetInfo.h" 24 | #include "llvm/MC/MCTargetAsmParser.h" 25 | #include "llvm/Support/CommandLine.h" 26 | #include "llvm/Support/FileUtilities.h" 27 | #include "llvm/Support/FormattedStream.h" 28 | #include "llvm/Support/Host.h" 29 | #include "llvm/Support/ManagedStatic.h" 30 | #include "llvm/Support/MemoryBuffer.h" 31 | #include "llvm/Support/PrettyStackTrace.h" 32 | #include "llvm/Support/Signals.h" 33 | #include "llvm/Support/SourceMgr.h" 34 | #include "llvm/Support/TargetRegistry.h" 35 | #include "llvm/Support/TargetSelect.h" 36 | #include "llvm/Support/ToolOutputFile.h" 37 | #include "llvm/Support/MemoryObject.h" 38 | 39 | #include "llvm/IR/BasicBlock.h" 40 | #include "llvm/IR/LLVMContext.h" 41 | #include "llvm/IR/Function.h" 42 | #include "llvm/IR/Module.h" 43 | #include "llvm/IR/IRBuilder.h" 44 | 45 | #include "llvm/PassManager.h" 46 | #include "llvm/Assembly/PrintModulePass.h" 47 | 48 | #include "lldc/ProxyMemoryObject.h" 49 | #include "lldc/SystemInformation.h" 50 | #include "lldc/BasicBlockCache.h" 51 | #include "lldc/GeneratedBasicBlocks.h" 52 | #include "lldc/ReverseTranslationConfiguration.h" 53 | #include "lldc/util.h" 54 | #include "lldc/PathState.h" 55 | #include "lldc/PathsManager.h" 56 | #include "lldc/ArmReverseTranslators.h" 57 | #include "lldc/InstructionDecoder.h" 58 | 59 | #define GET_REGINFO_ENUM 60 | #define GET_INSTRINFO_ENUM 61 | #include "ARMBaseInfo.h" 62 | 63 | 64 | using namespace llvm; 65 | 66 | int instrument_memory_access(const char * architecture, 67 | uint64_t entry_point, 68 | ProgramCounterRange * pc_ranges, 69 | uint64_t generated_code_address, 70 | ReadCodeMemoryFunc get_code_callback, 71 | void *opaque, 72 | GeneratedCode * generated_code, 73 | DictionaryElement * opts) 74 | { 75 | std::map cxx_opts; 76 | 77 | for (; opts != NULL && opts->key != NULL; opts++) 78 | { 79 | cxx_opts.insert(std::make_pair(opts->key, opts->value)); 80 | } 81 | //TODO: Address to link to not taken into account ... seems to be a bit more tricky, requires changes of the RuntimeDyld ... 82 | //TODO: opts not taken into account, should pass processor type etc through this 83 | std::list registerDescription; 84 | registerDescription.push_back(ProcessorRegisterDescription("R0.", Type::getInt32Ty(getGlobalContext()), 0, ARM::R0)); 85 | registerDescription.push_back(ProcessorRegisterDescription("R1.", Type::getInt32Ty(getGlobalContext()), 1, ARM::R1)); 86 | registerDescription.push_back(ProcessorRegisterDescription("R2.", Type::getInt32Ty(getGlobalContext()), 2, ARM::R2)); 87 | registerDescription.push_back(ProcessorRegisterDescription("R3.", Type::getInt32Ty(getGlobalContext()), 3, ARM::R3)); 88 | registerDescription.push_back(ProcessorRegisterDescription("R4.", Type::getInt32Ty(getGlobalContext()), 4, ARM::R4)); 89 | registerDescription.push_back(ProcessorRegisterDescription("R5.", Type::getInt32Ty(getGlobalContext()), 5, ARM::R5)); 90 | registerDescription.push_back(ProcessorRegisterDescription("R6.", Type::getInt32Ty(getGlobalContext()), 6, ARM::R6)); 91 | registerDescription.push_back(ProcessorRegisterDescription("R7.", Type::getInt32Ty(getGlobalContext()), 7, ARM::R7)); 92 | registerDescription.push_back(ProcessorRegisterDescription("R8.", Type::getInt32Ty(getGlobalContext()), 8, ARM::R8)); 93 | registerDescription.push_back(ProcessorRegisterDescription("R9.", Type::getInt32Ty(getGlobalContext()), 9, ARM::R9)); 94 | registerDescription.push_back(ProcessorRegisterDescription("R10.", Type::getInt32Ty(getGlobalContext()), 10, ARM::R10)); 95 | registerDescription.push_back(ProcessorRegisterDescription("R11.", Type::getInt32Ty(getGlobalContext()), 11, ARM::R11)); 96 | registerDescription.push_back(ProcessorRegisterDescription("R12.", Type::getInt32Ty(getGlobalContext()), 12, ARM::R12)); 97 | registerDescription.push_back(ProcessorRegisterDescription("SP.", Type::getInt32Ty(getGlobalContext()), 13, ARM::SP)); 98 | registerDescription.push_back(ProcessorRegisterDescription("LR.", Type::getInt32Ty(getGlobalContext()), 14, ARM::LR)); 99 | // registerDescription.push_back(ProcessorRegisterDescription("PC.", Type::getInt32Ty(getGlobalContext()), 15, ARM::PC)); 100 | registerDescription.push_back(ProcessorRegisterDescription("CPSR.", Type::getInt32Ty(getGlobalContext()), 15, ARM::CPSR)); 101 | 102 | BinaryTranslator instructionDecoder(architecture, new ProxyMemoryObject(get_code_callback, opaque), registerDescription, entry_point); 103 | 104 | if (cxx_opts.find("debug") != cxx_opts.end()) 105 | instructionDecoder.setDebug(true); 106 | 107 | std::list > list_pc_ranges; 108 | for (unsigned i = 0; pc_ranges[i].end != 0; i++) { 109 | list_pc_ranges.push_back(std::make_pair(pc_ranges[i].start, pc_ranges[i].end)); 110 | } 111 | Ranges cxx_pc_ranges(list_pc_ranges); 112 | instructionDecoder.translate(cxx_pc_ranges); 113 | 114 | if (cxx_opts.find("print_ir") != cxx_opts.end()) 115 | instructionDecoder.dumpIR(); 116 | 117 | 118 | // instructionDecoder.dumpIR(); 119 | if (cxx_opts.find("instrument_memory_access") != cxx_opts.end()) 120 | instructionDecoder.instrumentMemoryAccess(); 121 | // outs() << "TADAAAAAAA: ========================================================================================" << '\n'; 122 | // instructionDecoder.dumpIR(); 123 | CompiledCode* compiled_code = instructionDecoder.compile(); 124 | 125 | if (generated_code) 126 | { 127 | generated_code->code = (char *) malloc(compiled_code->getSize()); 128 | memcpy(generated_code->code, compiled_code->getData(), compiled_code->getSize()); 129 | generated_code->size = compiled_code->getSize(); 130 | generated_code->address = compiled_code->getAddress(); 131 | } 132 | // ReverseTranslateBasicBlock* state = instructionDecoder.genCodeEntry(entry_point); 133 | // // ReverseTranslateBasicBlock* state = genEntryFunctionCall(config, 0x650); 134 | // std::list states; 135 | // states.push_back(state); 136 | // std::list doneStates; 137 | // 138 | // NextInstructions nextInstructions; 139 | // try 140 | // { 141 | // instructionDecoder.translate(entry_point, pc_ranges); 142 | // // translateAll(&ram, config, static_cast(state)); 143 | // } 144 | // catch(ReverseTranslatorUknownOpcodeException ex) { 145 | // outs() << "Unknown opcode at address " << intToHexString(ex.getInstruction().getProgramCounter()) << "!!!!!!!" << '\n'; 146 | // // ex.getInstruction().dump_pretty(outs(), thumbAsmInfo.get(), thumbInstPrinter.get()); 147 | // // outs() << '\n'; 148 | // } 149 | // catch (...) { 150 | // outs() << "Other exception" << '\n'; 151 | // } 152 | // 153 | 154 | // reverseTranslationContext.currentBasicBlock->dump(); 155 | 156 | 157 | 158 | 159 | return 0; 160 | } 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /binary_translator/src/util.cpp: -------------------------------------------------------------------------------- 1 | #include "lldc/util.h" 2 | #include 3 | 4 | std::string intToHexString(uint64_t val) { 5 | std::stringstream ss; 6 | ss << "0x" << std::hex << val; 7 | return ss.str(); 8 | } 9 | -------------------------------------------------------------------------------- /binary_translator/test_translation.c: -------------------------------------------------------------------------------- 1 | #include "lldc/c_interface.h" 2 | 3 | #include 4 | #include 5 | 6 | 7 | 8 | unsigned read_code_memory(void *opaque, uint64_t address, unsigned size, uint8_t *buffer) 9 | { 10 | static const char buffer_0x1146[] = "\xa0\x89\x72\x49\x08\x43\xa0\x81\x60\x8b\xff" 11 | "\x22\x41\x32\x10\x43\x60\x83\x20\x8b\xf0\x21\x08\x40\x6e\x49\x40\x18\x20" 12 | "\x83\xa0\x8b\xc0\x0b\xc0\x03\x7d\x30\xa0\x83\x60\x8b\x30\x43\x60\x83\x60" 13 | "\x8b\xb0\x43\x60\x83\xa0\x8b\x01\x21\xc9\x03\x08\x43\xa0\x83\xa0\x8b\x40" 14 | "\x04\x40\x0c\xa0\x83\x00\x20\x63\x49\x40\x1c\x88\x42\xfc\xd3\xe0\x89\x61" 15 | "\x49\x80\x0b\x80\x03\x40\x18\xe0\x81\xa0\x88\x5f\x49\xc0\x0b\xc0\x03\x40" 16 | "\x18\xa0\x80\xe0\x88\x5d\x49\x08\x40\xff\x30\xc0\x1c\xe0\x80\x20\x89\x5b" 17 | "\x49\xc0\x0b\xc0\x03\x40\x18\x20\x81\x60\x89\x59\x49\xc0\x0b\xc0\x03\x40" 18 | "\x18\x60\x81\x20\x8f\x57\x49\xc0\x0b\xc0\x03\x40\x18\x20\x87\x60\x8b\x90" 19 | "\x43\x60\x83\xa0\x89\x40\x0a\x40\x02\x20\x30\xa0\x81\x52\x48\x01\x68\x49" 20 | "\x08\x49\x00\x01\x60\x00\x22\x42\x60\x4f\x49\x81\x60\x4f\x49\x01\x62\x4f" 21 | "\x49\x41\x62\x4f\x49\x01\x62\x01\x68\x39\x43\x01\x60\x01\x68\xc9\x07\xfc" 22 | "\xd0"; 23 | 24 | static const char buffer_0x128c[] = "\x00\x00\x0d\x40\x00\x08\x0a\x40\x40\x90\x01" 25 | "\x40\x00\x10\x0d\x40\xc8\x27\x00\x04\x80\x03\x0a\x40\xcc\x26\x00\x00\x84" 26 | "\x9c\x05\x06\x00\x00\x00\x00\x00\x2f\x04\x06\x80\x27\x01\x40\x00\x2a\x01" 27 | "\x40\xc0\x70\x03\x06\xc0\x1d\x00\x00\x9c\x03\x00\x04\x50\xc3\x05\x06\xac" 28 | "\xbf\x05\x06\x00\x30\x0d\x40\x40\x00\x10\x00\xb0\x1c\x00\x00\xbc\xc0\x05" 29 | "\x06\x07\x05\x00\x00\x96\xfa\xff\xff\x94\x00\x00\x04\x88\x03\x00\x04\x0d" 30 | "\x0a\x52\x73\x74\x20\x30\x78\x00\x00\x00\x00\x4d\x00\x00\x00\x00\x2b\x01" 31 | "\x40\x00\x90\x01\x40\x0d\xf0\xad\xde\xed\xfe\xad\xde\xc8\x03\x00\x04\xff" 32 | "\x01\x00\x00\x05\x39\x00\x00\xa0\x86\x01\x00\x6e\x2e\x00\x00\xc6\x7a\x00" 33 | "\x00\x01\xf8\xff\xff\x16\x0d\x00\x00\x42\x09\x00\x00\x0a\x19\x00\x00\x00" 34 | "\xa0\x0d\x40\x00\x00\xfe\x03\xff\xff\xff\x7f\x70\x47\x70\x47\xcc\x08\x00" 35 | "\x80\x00\x47\x01\x40\xa0\x00\x07\x40\x0a\x2b\x00\x00\x0b\x33\x00\x00\x0c" 36 | "\x2d\x00\x00\x36\x35\x00\x00\xaa\x72\x00\x00\x45\x4d\x00\x00\x6d\x71\x00" 37 | "\x00\x70\x47"; 38 | 39 | printf("Reading address 0x%llx[%d]\n", address, size); 40 | 41 | if (address >= 0x1146 && address < 0x1218) 42 | { 43 | memcpy(buffer, &buffer_0x1146[address - 0x1146], size); 44 | } 45 | else if (address >= 0x128c && address < 0x1372) 46 | { 47 | memcpy(buffer, &buffer_0x128c[address - 0x128c], size); 48 | } 49 | else 50 | { 51 | printf("Invalid address requested: 0x%llx\n", address); 52 | } 53 | 54 | return size; 55 | } 56 | 57 | int main(int argc, char ** argv) 58 | { 59 | ProgramCounterRange pc_ranges[2]; 60 | 61 | memset(pc_ranges, 0, sizeof(pc_ranges)); 62 | pc_ranges[0].start = 0x1146; 63 | pc_ranges[0].end = 0x1218; 64 | instrument_memory_access("thumb", 0x1146, pc_ranges, 0x2000, read_code_memory, NULL, NULL, NULL); 65 | } -------------------------------------------------------------------------------- /binary_translator/test_translation.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from binary_translator import instrument_memory_access 4 | 5 | memory_accesses = [] 6 | 7 | def read_code_memory(address, size): 8 | memory_accesses.append((address, size)) 9 | # print("Reading code memory 0x%08x[%d]" % (address, size)) 10 | if address >= 0x1146 and address < 0x1218: 11 | address -= 0x1146 12 | return bytes([160, 137, 114, 73, 8, 67, 160, 129, 96, 139, 255, 34, 13 | 65, 50, 16, 67, 96, 131, 32, 139, 240, 33, 8, 64, 110, 73, 14 | 64, 24, 32, 131, 160, 139, 192, 11, 192, 3, 125, 48, 160, 15 | 131, 96, 139, 48, 67, 96, 131, 96, 139, 176, 67, 96, 131, 16 | 160, 139, 1, 33, 201, 3, 8, 67, 160, 131, 160, 139, 64, 4, 17 | 64, 12, 160, 131, 0, 32, 99, 73, 64, 28, 136, 66, 252, 211, 18 | 224, 137, 97, 73, 128, 11, 128, 3, 64, 24, 224, 129, 160, 19 | 136, 95, 73, 192, 11, 192, 3, 64, 24, 160, 128, 224, 136, 20 | 93, 73, 8, 64, 255, 48, 192, 28, 224, 128, 32, 137, 91, 73, 21 | 192, 11, 192, 3, 64, 24, 32, 129, 96, 137, 89, 73, 192, 11, 22 | 192, 3, 64, 24, 96, 129, 32, 143, 87, 73, 192, 11, 192, 3, 23 | 64, 24, 32, 135, 96, 139, 144, 67, 96, 131, 160, 137, 64, 24 | 10, 64, 2, 32, 48, 160, 129, 82, 72, 1, 104, 73, 8, 73, 0, 25 | 1, 96, 0, 34, 66, 96, 79, 73, 129, 96, 79, 73, 1, 98, 79, 26 | 73, 65, 98, 79, 73, 1, 98, 1, 104, 57, 67, 1, 96, 1, 104, 27 | 201, 7, 252, 208][address : address + size]) 28 | elif address >= 0x128c and address < 0x1372: 29 | address -= 0x128c 30 | return bytes([0, 0, 13, 64, 0, 8, 10, 64, 64, 144, 1, 64, 0, 31 | 16, 13, 64, 200, 39, 0, 4, 128, 3, 10, 64, 204, 38, 0, 0, 32 | 132, 156, 5, 6, 0, 0, 0, 0, 0, 47, 4, 6, 128, 39, 1, 64, 33 | 0, 42, 1, 64, 192, 112, 3, 6, 192, 29, 0, 0, 156, 3, 0, 34 | 4, 80, 195, 5, 6, 172, 191, 5, 6, 0, 48, 13, 64, 64, 0, 35 | 16, 0, 176, 28, 0, 0, 188, 192, 5, 6, 7, 5, 0, 0, 150, 36 | 250, 255, 255, 148, 0, 0, 4, 136, 3, 0, 4, 13, 10, 82, 37 | 115, 116, 32, 48, 120, 0, 0, 0, 0, 77, 0, 0, 0, 0, 43, 38 | 1, 64, 0, 144, 1, 64, 13, 240, 173, 222, 237, 254, 173, 39 | 222, 200, 3, 0, 4, 255, 1, 0, 0, 5, 57, 0, 0, 160, 134, 1, 40 | 0, 110, 46, 0, 0, 198, 122, 0, 0, 1, 248, 255, 255, 22, 13, 41 | 0, 0, 66, 9, 0, 0, 10, 25, 0, 0, 0, 160, 13, 64, 0, 0, 42 | 254, 3, 255, 255, 255, 127, 112, 71, 112, 71, 204, 8, 0, 43 | 128, 0, 71, 1, 64, 160, 0, 7, 64, 10, 43, 0, 0, 11, 51, 44 | 0, 0, 12, 45, 0, 0, 54, 53, 0, 0, 170, 114, 0, 0, 69, 77, 45 | 0, 0, 109, 113, 0, 0, 112, 71][address : address + size]) 46 | else: 47 | print("Invalid address requested: 0x%x" % address) 48 | 49 | data = instrument_memory_access( 50 | architecture = "thumb", 51 | entry_point = 0x1146, 52 | valid_pc_ranges = [(0x1146, 0x1218)] , 53 | generated_code_address = 0x2000, 54 | get_code_callback = read_code_memory, 55 | opts = {"print_ir": "true", "debug": "true", "instrument_memory_access": "true"}) 56 | f = open("code.bin", "wb") 57 | f.write(data["generated_code"]) 58 | f.close() 59 | 60 | def merge_ranges(ranges): 61 | regions = [] 62 | 63 | for r in ranges: 64 | range_done = False 65 | for region in regions: 66 | if r[0] >= region[0] and r[0] <= region[1]: 67 | if r[1] > region[1]: 68 | region[1] = r[1] 69 | range_done = True 70 | break 71 | elif r[1] >= region[0] and r[1] <= region[1]: 72 | if r[0] < region[0]: 73 | region[0] = r[0] 74 | range_done = True 75 | break 76 | 77 | if not range_done: 78 | regions.append(r) 79 | 80 | if regions == ranges: 81 | return regions 82 | else: 83 | return merge_ranges(regions) 84 | 85 | bla = [[x, x + y] for (x, y) in memory_accesses] 86 | print([(hex(x), hex(y)) for [x, y] in merge_ranges(bla)]) 87 | 88 | #print(data) 89 | #print("Size: %d" % len(data['generated_code'])) 90 | #print(memory_accesses) 91 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from distutils.core import setup 3 | 4 | setup( 5 | name='avatar', 6 | version='0.1.0dev1', 7 | author='Jonas Zaddach', 8 | author_email='zaddach@eurecom.fr', 9 | packages=[ 'avatar', 10 | 'avatar/bintools', 11 | 'avatar/bintools.gdb', 12 | 'avatar/targets', 13 | 'avatar/plugins', 14 | 'avatar/util', 15 | 'avatar/interfaces', 16 | 'avatar/interfaces/gdb', 17 | 'avatar/interfaces/avatar_stub', 18 | 'avatar/emulators', 19 | 'avatar/emulators/s2e'], 20 | url='http://www.s3.eurecom.fr/tools/avatar/', 21 | license='Apache License 2.0', 22 | description='Dynamic firmware analysis', 23 | long_description=open('README.rst').read() 24 | ) 25 | --------------------------------------------------------------------------------