123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687 |
- #!/usr/bin/env python
- #
- # Copyright (C) 2011-2018 Intel Corporation. All rights reserved.
- #
- # Redistribution and use in source and binary forms, with or without
- # modification, are permitted provided that the following conditions
- # are met:
- #
- # * Redistributions of source code must retain the above copyright
- # notice, this list of conditions and the following disclaimer.
- # * Redistributions in binary form must reproduce the above copyright
- # notice, this list of conditions and the following disclaimer in
- # the documentation and/or other materials provided with the
- # distribution.
- # * Neither the name of Intel Corporation nor the names of its
- # contributors may be used to endorse or promote products derived
- # from this software without specific prior written permission.
- #
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- #
- #
- from __future__ import print_function
- import gdb
- import struct
- import os.path
- from ctypes import create_string_buffer
- import load_symbol_cmd
- import sgx_emmt
- import ctypes
- # Calculate the bit mode of current debuggee project
- SIZE = gdb.parse_and_eval("sizeof(long)")
- ET_SIM = 0x1
- ET_DEBUG = 0x2
- PAGE_SIZE = 0x1000
- KB_SIZE = 1024
- # The following definitions should strictly align with the structure of
- # debug_enclave_info_t in uRTS.
- # Here we only care about the first 7 items in the structure.
- # pointer: next_enclave_info, start_addr, tcs_list, lpFileName,
- # g_peak_heap_used_addr
- # int32_t: enclave_type, file_name_size
- ENCLAVE_INFO_SIZE = 5 * 8 + 2 * 4
- INFO_FMT = 'QQQIIQQ'
- ENCLAVES_ADDR = {}
- # The following definitions should strictly align with the struct of
- # tcs_t
- # Here we only care about the first 8 items in the structure
- # uint64_t: state, flags, ossa, oentry, aep, ofs_base
- # uint32_t: nssa, cssa
- ENCLAVE_TCS_INFO_SIZE = 6*8 + 2*4
- TCS_INFO_FMT = 'QQQIIQQQ'
- def get_inferior():
- """Get current inferior"""
- try:
- if len(gdb.inferiors()) == 0:
- print ("No gdb inferior could be found.")
- return -1
- else:
- inferior = gdb.inferiors()[0]
- return inferior
- except AttributeError:
- print ("This gdb's python support is too old, please update first.")
- exit()
- def read_from_memory(addr, size):
- """Read data with specified size from the specified meomory"""
- inferior = get_inferior()
- # actually we can check the addr more securely
- # ( check the address is inside the enclave)
- if inferior == -1 or addr == 0:
- print ("Error happens in read_from_memory: addr = {0:x}".format(int(addr)))
- return None
- try:
- string = inferior.read_memory(addr, size)
- return string
- except gdb.MemoryError:
- print ("Can't access memory at {0:x}.".format(int(addr)))
- return None
- def write_to_memory(addr, buf):
- """Write a specified buffer to the specified memory"""
- inferior = get_inferior()
- if inferior == -1 or addr == 0:
- print ("Error happens in write_to_memory: addr = {0:x}".format(int(addr)))
- return -1
- try:
- inferior.write_memory(addr, buf)
- return 0
- except gdb.MemoryError:
- print ("Can't access memory at {0:x}.".format(int(addr)))
- return -1
- def target_path_to_host_path(target_path):
- so_name = os.path.basename(target_path)
- strpath = gdb.execute("show solib-search-path", False, True)
- path = strpath.split()[-1]
- strlen = len(path)
- if strlen != 1:
- path = path[0:strlen-1]
- host_path = path + "/" + so_name
- #strlen = len(host_path)
- #host_path = host_path[0:strlen-7]
- return host_path
- class enclave_info(object):
- """Class to contain the enclave inforation,
- such as start address, stack addresses, stack size, etc.
- The enclave information is for one enclave."""
- def __init__(self, _next_ei, _start_addr, _enclave_type, _stack_addr_list, \
- _stack_size, _enclave_path, _heap_addr, _tcs_addr_list):
- self.next_ei = _next_ei
- self.start_addr = _start_addr
- self.enclave_type = _enclave_type
- self.stack_addr_list = _stack_addr_list
- self.stack_size = _stack_size
- self.enclave_path = _enclave_path
- self.heap_addr = _heap_addr
- self.tcs_addr_list = _tcs_addr_list
- def __str__(self):
- print ("stack address list = {0:s}".format(self.stack_addr_list))
- return "start_addr = %#x, enclave_path = \"%s\", stack_size = %d" \
- % (self.start_addr, self.enclave_path, self.stack_size)
- def __eq__(self, other):
- if other == None:
- return False
- if self.start_addr == other.start_addr:
- return True
- else:
- return False
- def init_enclave_debug(self):
- # Only product HW enclave can't be debugged
- if (self.enclave_type & ET_SIM) != ET_SIM and (self.enclave_type & ET_DEBUG) != ET_DEBUG:
- print ('Warning: {0:s} is a product hardware enclave. It can\'t be debugged and sgx_emmt doesn\'t work'.format(self.enclave_path))
- return -1
- # set TCS debug flag
- for tcs_addr in self.tcs_addr_list:
- string = read_from_memory(tcs_addr + 8, 4)
- if string == None:
- return 0
- flag = struct.unpack('I', string)[0]
- flag |= 1
- gdb_cmd = "set *(unsigned int *)%#x = %#x" %(tcs_addr + 8, flag)
- gdb.execute(gdb_cmd, False, True)
- #If it is a product enclave, won't reach here.
- #load enclave symbol
- if os.path.exists(self.enclave_path) == True:
- enclave_path = self.enclave_path
- else:
- enclave_path = target_path_to_host_path(self.enclave_path)
- gdb_cmd = load_symbol_cmd.GetLoadSymbolCommand(enclave_path, str(self.start_addr))
- if gdb_cmd == -1:
- return 0
- print (gdb_cmd)
- gdb.execute(gdb_cmd, False, True)
- global ENCLAVES_ADDR
- ENCLAVES_ADDR[self.start_addr] = gdb_cmd.split()[2]
- return 0
- def get_peak_heap_used(self):
- """Get the peak value of the heap used"""
- if self.heap_addr == 0:
- return -2
- # read the peak_heap_used value
- string = read_from_memory(self.heap_addr, SIZE)
- if string == None:
- return -1
- if SIZE == 4:
- fmt = 'I'
- elif SIZE == 8:
- fmt = "Q"
- peak_heap_used = struct.unpack(fmt, string)[0]
- return peak_heap_used
- def internal_compare (self, a, b):
- return (a > b) - (a < b)
- def find_boundary_page_index(self, stack_addr, stack_size):
- """Find the unused page index of the boundary for the used and unused pages
- with the binary search algorithm"""
- page_index = -1 #record the last unused page index
- low = 0
- high = (stack_size>>12) - 1
- mid = 0
- # Read the mid page and check if it is used or not
- # If the mid page is used, then continue to search [mid+1, high]
- while low <= high:
- #print "low = %x, high = %x, mid = %x" % (low, high, mid)
- mid = (low + high)>>1
- string = read_from_memory(stack_addr + mid*PAGE_SIZE + (PAGE_SIZE>>1), PAGE_SIZE>>1)
- if string == None:
- return -2
- dirty_flag = 0
- for i in range(0, PAGE_SIZE>>4):
- temp = struct.unpack_from("Q", string, ((PAGE_SIZE>>4) - 1 - i)*8)[0]
- if (self.internal_compare(temp, 0xcccccccccccccccc)) != 0:
- dirty_flag = 1
- break
- if dirty_flag == 0:
- low = mid + 1
- page_index = mid
- else:
- high = mid -1
- return page_index
- def get_peak_stack_used(self):
- """Get the peak value of the stack used"""
- peak_stack_used = 0
- for tcs_addr in self.tcs_addr_list:
- tcs_str = read_from_memory(tcs_addr, ENCLAVE_TCS_INFO_SIZE)
- if tcs_str == None:
- return -1
- tcs_tuple = struct.unpack_from(TCS_INFO_FMT, tcs_str)
- offset = tcs_tuple[7]
- if SIZE == 4:
- td_fmt = '20I'
- elif SIZE == 8:
- td_fmt = '20Q'
- td_str = read_from_memory(self.start_addr+offset, (20*SIZE))
- if td_str == None:
- return -1
- td_tuple = struct.unpack_from(td_fmt, td_str)
- stack_commit_addr = td_tuple[19]
- stack_base_addr = td_tuple[2]
- stack_limit_addr = td_tuple[3]
- stack_usage = 0
- if stack_commit_addr > stack_limit_addr:
- stack_base_addr_page_align = (stack_base_addr + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)
- stack_usage = stack_base_addr_page_align - stack_commit_addr
- elif stack_limit_addr != 0:
- page_index = self.find_boundary_page_index(stack_limit_addr, self.stack_size)
- if page_index == (self.stack_size)/PAGE_SIZE - 1:
- continue
- elif page_index == -2:
- return -1
- else:
- string = read_from_memory(stack_limit_addr + (page_index+1) * PAGE_SIZE, PAGE_SIZE)
- if string == None:
- return -1
- for i in range(0, len(string)):
- temp = struct.unpack_from("B", string, i)[0]
- if (self.internal_compare(temp, 0xcc)) != 0:
- stack_usage = self.stack_size - (page_index+1) * PAGE_SIZE - i
- break
- if peak_stack_used < stack_usage:
- peak_stack_used = stack_usage
- return peak_stack_used
- def show_emmt(self):
- ret = gdb.execute("show sgx_emmt", False, True)
- if ret.strip() == "sgx_emmt enabled":
- print ("Enclave: \"{0:s}\"".format(self.enclave_path))
- peak_stack_used = self.get_peak_stack_used()
- if peak_stack_used == -1:
- print ("Failed to collect the stack usage information for \"{0:s}\"".format(self.enclave_path))
- else:
- peak_stack_used_align = (peak_stack_used + KB_SIZE - 1) & ~(KB_SIZE - 1)
- print (" [Peak stack used]: {0:d} KB".format(peak_stack_used_align >> 10))
- peak_heap_used = self.get_peak_heap_used()
- if peak_heap_used == -1:
- print ("Failed to collect the heap usage information for \"{0:s}\"".format(self.enclave_path))
- elif peak_heap_used == -2:
- print (" [Can't get peak heap used]: You may use version script to control symbol export. Please export \'g_peak_heap_used\' in your version script.")
- else:
- peak_heap_used_align = (peak_heap_used + KB_SIZE - 1) & ~(KB_SIZE - 1)
- print (" [Peak heap used]: {0:d} KB".format(peak_heap_used_align >> 10))
- def fini_enclave_debug(self):
- # If it is HW product enclave, nothing to do
- if (self.enclave_type & ET_SIM) != ET_SIM and (self.enclave_type & ET_DEBUG) != ET_DEBUG:
- return -2
- self.show_emmt()
- try:
- # clear TCS debug flag
- for tcs_addr in self.tcs_addr_list:
- string = read_from_memory(tcs_addr + 8, 4)
- if string == None:
- return -2
- flag = struct.unpack('I', string)[0]
- flag &= (~1)
- gdb_cmd = "set *(unsigned int *)%#x = %#x" %(tcs_addr + 8, flag)
- gdb.execute(gdb_cmd, False, True)
- #unload symbol
- if os.path.exists(self.enclave_path) == True:
- enclave_path = self.enclave_path
- else:
- enclave_path = target_path_to_host_path(self.enclave_path)
- gdb_cmd = load_symbol_cmd.GetUnloadSymbolCommand(enclave_path, str(self.start_addr))
- if gdb_cmd == -1:
- return -1
- print (gdb_cmd)
- try:
- gdb.execute(gdb_cmd, False, True)
- global ENCLAVES_ADDR
- del ENCLAVES_ADDR[self.start_addr]
- except gdb.error:
- print ("Old gdb doesn't support remove-file-symbol command")
- return 0
- ##It is possible enclave has been destroyed, so may raise exception on memory access
- except gdb.MemoryError:
- return -1
- except:
- return -1
- def append_tcs_list(self, tcs_addr):
- for tcs_tmp in self.tcs_addr_list:
- if tcs_tmp == tcs_addr:
- return 0
- self.tcs_addr_list.append(tcs_addr)
- return 0
- def retrieve_enclave_info(info_addr = 0):
- """retrieve one enclave info"""
- # Step 1: find the enclave info address
- if info_addr == 0:
- if SIZE == 4:
- info_addr = gdb.parse_and_eval("$eax")
- elif SIZE == 8:
- info_addr = gdb.parse_and_eval("$rdi")
- # Step 2: retrieve the enclave info
- info_str = read_from_memory(info_addr, ENCLAVE_INFO_SIZE)
- if info_str == None:
- return None
- info_tuple = struct.unpack_from(INFO_FMT, info_str, 0)
- # (next_enclave_info,start_addr,tcs_list,enclave_type,file_name_size,
- # lpFileName,g_peak_heap_used_addr)
- #print "next_addr: %#x, start_addr: %#x, tcs_list: %#x, enclave_type:%#x, file_name_size: %#x," \
- # % (info_tuple[0], info_tuple[1], info_tuple[2], info_tuple[3], info_tuple[4])
- #print "name_addr: %#x, peak_heap_used_addr: %#x" \
- # % (info_tuple[5], info_tuple[6])
- #get enclave path
- name_str = read_from_memory(info_tuple[5], info_tuple[4])
- if name_str == None:
- return None
- fmt = str(info_tuple[4]) + 's'
- enclave_path = struct.unpack_from(fmt, name_str)[0].decode(encoding='UTF-8')
- # get the stack addr list
- stack_addr_list = []
- tcs_addr_list = []
- if SIZE == 4:
- fmt = '3I'
- elif SIZE == 8:
- fmt = '3Q'
- tcs_info_addr = info_tuple[2]
- if tcs_info_addr == 0:
- print ("Error: tcs info address = {0:x}".format(tcs_info_addr))
- return None
- stacksize = 0;
- while tcs_info_addr is not 0:
- tcs_info_str = read_from_memory(tcs_info_addr, 3*SIZE)
- if tcs_info_str == None:
- return None
- tcs_info_tuple = struct.unpack_from(fmt, tcs_info_str)
- #get tcs struct data
- tcs_t_str = read_from_memory(tcs_info_tuple[1], ENCLAVE_TCS_INFO_SIZE)
- if tcs_t_str == None:
- return None
- tcs_t_tuple = struct.unpack_from(TCS_INFO_FMT, tcs_t_str)
- if SIZE == 4:
- td_fmt = '4I'
- elif SIZE == 8:
- td_fmt = '4Q'
- #get thread_data_t address
- td_addr = tcs_t_tuple[7] + info_tuple[1] #thread_data_t = tcs.of_base + debug_enclave_info.start_addr
- td_str = read_from_memory(td_addr, (4*SIZE))
- if td_str == None:
- return None
- td_tuple = struct.unpack_from(td_fmt, td_str)
- #print ("thread_info:%#x, last_sp:%#x, stack_base_addr:%#x, stack_limit_addr:%#x" \
- # % (td_tuple[0], td_tuple[1], td_tuple[2], td_tuple[3]));
- if td_tuple[2] != td_tuple[3]:
- #stack size = ROUND_TO_PAGE(stack_base_addr - stack_limit_addr) since we have
- #a static stack whose size is smaller than PAGE_SIZE
- stacksize = (td_tuple[2] - td_tuple[3] + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)
- stack_addr_list.append(td_tuple[3]) #use stack limit addr as stack base address
- tcs_addr_list.append(tcs_info_tuple[1])
- tcs_info_addr = tcs_info_tuple[0]
- last_ocall_frame = tcs_info_tuple[2]
- last_frame = last_ocall_frame
- #print ("last_ocall_frame = {0:x}".format(last_ocall_frame))
- while last_ocall_frame is not 0:
- if SIZE == 4:
- of_fmt = '4I'
- elif SIZE == 8:
- of_fmt = '4Q'
- ocall_frame = read_from_memory(last_ocall_frame, 4*SIZE)
- if ocall_frame == None:
- return None
- ocall_frame_tuple = struct.unpack_from(of_fmt, ocall_frame)
- last_frame = ocall_frame_tuple[0]
- last_trusted_ocall_frame = td_tuple[1]
- #print ("last_trusted_ocall_frame = {0:x}".format(last_trusted_ocall_frame))
- #print ("td_tuple[2] = {0:x}".format(td_tuple[2]))
- #break
- while last_trusted_ocall_frame != td_tuple[2]:
- if SIZE == 4:
- oc_fmt = '20I'
- ret_addr_of_fmt = 'I'
- elif SIZE == 8:
- oc_fmt = '20Q'
- ret_addr_of_fmt = 'Q'
- oc_str = read_from_memory(last_trusted_ocall_frame, 20*SIZE)
- if oc_str == None:
- return None
- oc_tuple = struct.unpack_from(oc_fmt, oc_str)
- last_trusted_ocall_frame = oc_tuple[6]
- #print ("last_trusted_ocall_frame = {0:x}".format(last_trusted_ocall_frame))
- #print ("ocall_frame_tuple[1] = {0:x}".format(ocall_frame_tuple[1]))
- #print ("oc_tuple[18] = {0:x}".format(oc_tuple[18]))
- #break
- if ocall_frame_tuple[1] == oc_tuple[18]:
- #ocall_frame.pre_last_frame = 0
- #ocall_frame.ret = ocall_context.ocall_ret
- #ocall_frame.xbp = ocall_context.xbp
- xbp = oc_tuple[11]
- ret_addr_str = read_from_memory(xbp + SIZE, SIZE)
- if ret_addr_str == None:
- return None
- ret_addr_tuple = struct.unpack_from(ret_addr_of_fmt, ret_addr_str)
- gdb_cmd = "set *(uintptr_t *)%#x = 0" %(int(last_ocall_frame))
- gdb.execute(gdb_cmd, False, True)
- gdb_cmd = "set *(uintptr_t *)%#x = %#x" %(int(last_ocall_frame+(2*SIZE)), xbp)
- gdb.execute(gdb_cmd, False, True)
- gdb_cmd = "set *(uintptr_t *)%#x = %#x" %(int(last_ocall_frame+(3*SIZE)), ret_addr_tuple[0])
- gdb.execute(gdb_cmd, False, True)
- break
- last_ocall_frame = last_frame
- node = enclave_info(info_tuple[0], info_tuple[1], info_tuple[3], stack_addr_list, \
- stacksize, enclave_path, info_tuple[6], tcs_addr_list)
- return node
- def handle_load_event():
- """Handle the enclave loading event.
- Firstly, retrieve the enclave info node from register
- """
- node = retrieve_enclave_info()
- if node != None:
- node.init_enclave_debug()
- else:
- return
- def handle_unload_event():
- node = retrieve_enclave_info()
- if node != None:
- node.fini_enclave_debug()
- else:
- return
- def is_bp_in_urts():
- try:
- ip = gdb.parse_and_eval("$pc")
- solib_name = gdb.solib_name(int(str(ip).split()[0], 16))
- if(solib_name.find("libsgx_urts.so") == -1 and solib_name.find("libsgx_urts_sim.so") == -1 and solib_name.find("libsgx_aesm_service.so") == -1):
- return False
- else:
- return True
- #If exception happens, just assume it is bp in uRTS.
- except:
- return True
- def init_enclaves_debug():
- #execute "set displaced-stepping off" to workaround the gdb 7.11 issue
- gdb.execute("set displaced-stepping off", False, True)
- enclave_info_addr = gdb.parse_and_eval("*(void**)&g_debug_enclave_info_list")
- while enclave_info_addr != 0:
- node = retrieve_enclave_info(enclave_info_addr)
- if node != None:
- node.init_enclave_debug()
- else:
- return
- enclave_info_addr = node.next_ei
- return
- class detach_enclaves (gdb.Command):
- def __init__ (self):
- gdb.Command.__init__ (self, "detach_enclaves", gdb.COMMAND_NONE)
- def invoke (self, arg, from_tty):
- #We reject the command from the input of terminal
- if from_tty == True:
- return
- try:
- enclave_info_addr = gdb.parse_and_eval("*(void**)&g_debug_enclave_info_list")
- except:
- return
- while enclave_info_addr != 0:
- node = retrieve_enclave_info(enclave_info_addr)
- if node != None:
- node.fini_enclave_debug()
- else:
- return
- enclave_info_addr = node.next_ei
- class UpdateOcallFrame(gdb.Breakpoint):
- def __init__(self):
- gdb.Breakpoint.__init__ (self, spec="notify_gdb_to_update", internal=1)
- def stop(self):
- bp_in_urts = is_bp_in_urts()
- if bp_in_urts == True:
- if SIZE == 4:
- base_addr = gdb.parse_and_eval("$eax")
- tcs_addr = gdb.parse_and_eval("$edx")
- ocall_frame = gdb.parse_and_eval("$ecx")
- elif SIZE == 8:
- base_addr = gdb.parse_and_eval("$rdi")
- tcs_addr = gdb.parse_and_eval("$rsi")
- ocall_frame = gdb.parse_and_eval("$rdx")
- #print ("base_addr = {0:x}".format(int(base_addr)))
- #print ("tcs_addr = {0:x}".format(int(tcs_addr)))
- #print ("ocall_frame = {0:x}".format(int(ocall_frame)))
- tcs_str = read_from_memory(tcs_addr, ENCLAVE_TCS_INFO_SIZE)
- if tcs_str == None:
- return False
- tcs_tuple = struct.unpack_from(TCS_INFO_FMT, tcs_str)
- offset = tcs_tuple[7]
- if SIZE == 4:
- td_fmt = '4I'
- elif SIZE == 8:
- td_fmt = '4Q'
- td_str = read_from_memory(base_addr+offset, (4*SIZE))
- if td_str == None:
- return False
- td_tuple = struct.unpack_from(td_fmt, td_str)
- if SIZE == 4:
- trusted_of_fmt = '20I'
- ret_addr_of_fmt = 'I'
- elif SIZE == 8:
- trusted_of_fmt = '20Q'
- ret_addr_of_fmt = 'Q'
- last_sp = td_tuple[1]
- trusted_ocall_frame = read_from_memory(last_sp, (20*SIZE))
- if trusted_ocall_frame == None:
- return False
- trusted_ocall_frame_tuple = struct.unpack_from(trusted_of_fmt, trusted_ocall_frame)
- xbp = trusted_ocall_frame_tuple[11]
- ret_addr_str = read_from_memory(xbp + SIZE, SIZE)
- if ret_addr_str == None:
- return False
- ret_addr_tuple = struct.unpack_from(ret_addr_of_fmt, ret_addr_str)
- gdb_cmd = "set *(uintptr_t *)%#x = 0" %(int(ocall_frame))
- gdb.execute(gdb_cmd, False, True)
- gdb_cmd = "set *(uintptr_t *)%#x = %#x" %(int(ocall_frame+(2*SIZE)), xbp)
- gdb.execute(gdb_cmd, False, True)
- gdb_cmd = "set *(uintptr_t *)%#x = %#x" %(int(ocall_frame+(3*SIZE)), ret_addr_tuple[0])
- gdb.execute(gdb_cmd, False, True)
- return False
- class LoadEventBreakpoint(gdb.Breakpoint):
- def __init__(self):
- gdb.Breakpoint.__init__ (self, spec="sgx_debug_load_state_add_element", internal=1)
- def stop(self):
- bp_in_urts = is_bp_in_urts()
- if bp_in_urts == True:
- handle_load_event()
- return False
- class UnloadEventBreakpoint(gdb.Breakpoint):
- def __init__(self):
- gdb.Breakpoint.__init__ (self, spec="sgx_debug_unload_state_remove_element", internal=1)
- def stop(self):
- bp_in_urts = is_bp_in_urts()
- if bp_in_urts == True:
- handle_unload_event()
- return False
-
- class GetTCSBreakpoint(gdb.Breakpoint):
- def __init__(self):
- gdb.Breakpoint.__init__ (self, spec="urts_add_tcs", internal=1) # sgx_add_tcs should be fastcall
- def stop(self):
- bp_in_urts = is_bp_in_urts()
- if bp_in_urts == True:
- if SIZE == 4:
- tcs_addr_1 = gdb.parse_and_eval("$eax")
- tcs_addr = ctypes.c_uint32(tcs_addr_1).value
- elif SIZE == 8:
- tcs_addr_1 = gdb.parse_and_eval("$rdi")
- tcs_addr = ctypes.c_uint64(tcs_addr_1).value
- enclave_info_addr = gdb.parse_and_eval("*(void **)&g_debug_enclave_info_list")
- if enclave_info_addr != 0:
- node = retrieve_enclave_info(enclave_info_addr)
- else:
- return False
- if node != None:
- node.append_tcs_list(tcs_addr)
- string = read_from_memory(tcs_addr + 8, 4)
- if string == None:
- return False
- flag = struct.unpack('I', string)[0]
- flag |= 1
- gdb_cmd = "set *(unsigned int *)%#x = %#x" %(tcs_addr + 8, flag)
- gdb.execute(gdb_cmd, False, True)
- return False
-
- def sgx_debugger_init():
- print ("detect urts is loaded, initializing")
- global SIZE
- SIZE = gdb.parse_and_eval("sizeof(long)")
- inited = 0
- bps = gdb.breakpoints()
- if None != bps:
- for bp in bps:
- if bp.location == "sgx_debug_load_state_add_element":
- inited = 1
- break
- if inited == 0:
- detach_enclaves()
- gdb.execute("source gdb_sgx_cmd", False, True)
- UpdateOcallFrame()
- LoadEventBreakpoint()
- UnloadEventBreakpoint()
- GetTCSBreakpoint()
- gdb.events.exited.connect(exit_handler)
- init_enclaves_debug()
- def exit_handler(event):
- # When the inferior exited, remove all enclave symbol
- for key in list(ENCLAVES_ADDR.keys()):
- gdb.execute("remove-symbol-file -a %s" % (ENCLAVES_ADDR[key]), False, True)
- ENCLAVES_ADDR.clear()
- def newobj_handler(event):
- solib_name = os.path.basename(event.new_objfile.filename)
- if solib_name == 'libsgx_urts.so' or solib_name == 'libsgx_urts_sim.so' or solib_name == 'libsgx_aesm_service.so':
- sgx_debugger_init()
- return
- if __name__ == "__main__":
- gdb.events.new_objfile.connect(newobj_handler)
- sgx_emmt.init_emmt()
|