├── .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