gdb_sgx_plugin.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. #!/usr/bin/env python
  2. #
  3. # Copyright (C) 2011-2017 Intel Corporation. All rights reserved.
  4. #
  5. # Redistribution and use in source and binary forms, with or without
  6. # modification, are permitted provided that the following conditions
  7. # are met:
  8. #
  9. # * Redistributions of source code must retain the above copyright
  10. # notice, this list of conditions and the following disclaimer.
  11. # * Redistributions in binary form must reproduce the above copyright
  12. # notice, this list of conditions and the following disclaimer in
  13. # the documentation and/or other materials provided with the
  14. # distribution.
  15. # * Neither the name of Intel Corporation nor the names of its
  16. # contributors may be used to endorse or promote products derived
  17. # from this software without specific prior written permission.
  18. #
  19. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. #
  31. #
  32. from __future__ import print_function
  33. import gdb
  34. import struct
  35. import os.path
  36. from ctypes import create_string_buffer
  37. import load_symbol_cmd
  38. import sgx_emmt
  39. # Calculate the bit mode of current debuggee project
  40. SIZE = gdb.parse_and_eval("sizeof(long)")
  41. ET_SIM = 0x1
  42. ET_DEBUG = 0x2
  43. PAGE_SIZE = 0x1000
  44. KB_SIZE = 1024
  45. # The following definitions should strictly align with the structure of
  46. # debug_enclave_info_t in uRTS.
  47. # Here we only care about the first 7 items in the structure.
  48. # pointer: next_enclave_info, start_addr, tcs_list, lpFileName,
  49. # g_peak_heap_used_addr
  50. # int32_t: enclave_type, file_name_size
  51. ENCLAVE_INFO_SIZE = 5 * 8 + 2 * 4
  52. INFO_FMT = 'QQQIIQQ'
  53. ENCLAVES_ADDR = {}
  54. # The following definitions should strictly align with the struct of
  55. # tcs_t
  56. # Here we only care about the first 8 items in the structure
  57. # uint64_t: state, flags, ossa, oentry, aep, ofs_base
  58. # uint32_t: nssa, cssa
  59. ENCLAVE_TCS_INFO_SIZE = 6*8 + 2*4
  60. TCS_INFO_FMT = 'QQQIIQQQ'
  61. def get_inferior():
  62. """Get current inferior"""
  63. try:
  64. if len(gdb.inferiors()) == 0:
  65. print ("No gdb inferior could be found.")
  66. return -1
  67. else:
  68. inferior = gdb.inferiors()[0]
  69. return inferior
  70. except AttributeError:
  71. print ("This gdb's python support is too old, please update first.")
  72. exit()
  73. def read_from_memory(addr, size):
  74. """Read data with specified size from the specified meomory"""
  75. inferior = get_inferior()
  76. # actually we can check the addr more securely
  77. # ( check the address is inside the enclave)
  78. if inferior == -1 or addr == 0:
  79. print ("Error happens in read_from_memory: addr = {0:x}".format(int(addr)))
  80. return None
  81. try:
  82. string = inferior.read_memory(addr, size)
  83. return string
  84. except gdb.MemoryError:
  85. print ("Can't access memory at {0:x}.".format(int(addr)))
  86. return None
  87. def write_to_memory(addr, buf):
  88. """Write a specified buffer to the specified memory"""
  89. inferior = get_inferior()
  90. if inferior == -1 or addr == 0:
  91. print ("Error happens in write_to_memory: addr = {0:x}".format(int(addr)))
  92. return -1
  93. try:
  94. inferior.write_memory(addr, buf)
  95. return 0
  96. except gdb.MemoryError:
  97. print ("Can't access memory at {0:x}.".format(int(addr)))
  98. return -1
  99. def target_path_to_host_path(target_path):
  100. so_name = os.path.basename(target_path)
  101. strpath = gdb.execute("show solib-search-path", False, True)
  102. path = strpath.split()[-1]
  103. strlen = len(path)
  104. if strlen != 1:
  105. path = path[0:strlen-1]
  106. host_path = path + "/" + so_name
  107. #strlen = len(host_path)
  108. #host_path = host_path[0:strlen-7]
  109. return host_path
  110. class enclave_info(object):
  111. """Class to contain the enclave inforation,
  112. such as start address, stack addresses, stack size, etc.
  113. The enclave information is for one enclave."""
  114. def __init__(self, _next_ei, _start_addr, _enclave_type, _stack_addr_list, \
  115. _stack_size, _enclave_path, _heap_addr, _tcs_addr_list):
  116. self.next_ei = _next_ei
  117. self.start_addr = _start_addr
  118. self.enclave_type = _enclave_type
  119. self.stack_addr_list = _stack_addr_list
  120. self.stack_size = _stack_size
  121. self.enclave_path = _enclave_path
  122. self.heap_addr = _heap_addr
  123. self.tcs_addr_list = _tcs_addr_list
  124. def __str__(self):
  125. print ("stack address list = {0:s}".format(self.stack_addr_list))
  126. return "start_addr = %#x, enclave_path = \"%s\", stack_size = %d" \
  127. % (self.start_addr, self.enclave_path, self.stack_size)
  128. def __eq__(self, other):
  129. if other == None:
  130. return False
  131. if self.start_addr == other.start_addr:
  132. return True
  133. else:
  134. return False
  135. def init_enclave_debug(self):
  136. # Only product HW enclave can't be debugged
  137. if (self.enclave_type & ET_SIM) != ET_SIM and (self.enclave_type & ET_DEBUG) != ET_DEBUG:
  138. print ('Warning: {0:s} is a product hardware enclave. It can\'t be debugged and sgx_emmt doesn\'t work'.format(self.enclave_path))
  139. return -1
  140. # set TCS debug flag
  141. for tcs_addr in self.tcs_addr_list:
  142. string = read_from_memory(tcs_addr + 8, 4)
  143. if string == None:
  144. return 0
  145. flag = struct.unpack('I', string)[0]
  146. flag |= 1
  147. gdb_cmd = "set *(unsigned int *)%#x = %#x" %(tcs_addr + 8, flag)
  148. gdb.execute(gdb_cmd, False, True)
  149. #If it is a product enclave, won't reach here.
  150. #load enclave symbol
  151. if os.path.exists(self.enclave_path) == True:
  152. enclave_path = self.enclave_path
  153. else:
  154. enclave_path = target_path_to_host_path(self.enclave_path)
  155. gdb_cmd = load_symbol_cmd.GetLoadSymbolCommand(enclave_path, str(self.start_addr))
  156. if gdb_cmd == -1:
  157. return 0
  158. print (gdb_cmd)
  159. gdb.execute(gdb_cmd, False, True)
  160. global ENCLAVES_ADDR
  161. ENCLAVES_ADDR[self.start_addr] = gdb_cmd.split()[2]
  162. return 0
  163. def get_peak_heap_used(self):
  164. """Get the peak value of the heap used"""
  165. if self.heap_addr == 0:
  166. return -2
  167. # read the peak_heap_used value
  168. string = read_from_memory(self.heap_addr, SIZE)
  169. if string == None:
  170. return -1
  171. if SIZE == 4:
  172. fmt = 'I'
  173. elif SIZE == 8:
  174. fmt = "Q"
  175. peak_heap_used = struct.unpack(fmt, string)[0]
  176. return peak_heap_used
  177. def internal_compare (self, a, b):
  178. return (a > b) - (a < b)
  179. def find_boundary_page_index(self, stack_addr, stack_size):
  180. """Find the unused page index of the boundary for the used and unused pages
  181. with the binary search algorithm"""
  182. page_index = -1 #record the last unused page index
  183. low = 0
  184. high = (stack_size>>12) - 1
  185. mid = 0
  186. # Read the mid page and check if it is used or not
  187. # If the mid page is used, then continue to search [mid+1, high]
  188. while low <= high:
  189. #print "low = %x, high = %x, mid = %x" % (low, high, mid)
  190. mid = (low + high)>>1
  191. string = read_from_memory(stack_addr + mid*PAGE_SIZE + (PAGE_SIZE>>1), PAGE_SIZE>>1)
  192. if string == None:
  193. return -2
  194. dirty_flag = 0
  195. for i in range(0, PAGE_SIZE>>4):
  196. temp = struct.unpack_from("Q", string, ((PAGE_SIZE>>4) - 1 - i)*8)[0]
  197. if (self.internal_compare(temp, 0xcccccccccccccccc)) != 0:
  198. dirty_flag = 1
  199. break
  200. if dirty_flag == 0:
  201. low = mid + 1
  202. page_index = mid
  203. else:
  204. high = mid -1
  205. return page_index
  206. def get_peak_stack_used(self):
  207. """Get the peak value of the stack used"""
  208. peak_stack_used = 0
  209. gen = (addr for addr in self.stack_addr_list if addr != 0)
  210. for stack_addr in gen:
  211. page_index = self.find_boundary_page_index(stack_addr, self.stack_size)
  212. if page_index == (self.stack_size)/PAGE_SIZE - 1:
  213. continue
  214. elif page_index == -2:
  215. return -1
  216. else:
  217. string = read_from_memory(stack_addr + (page_index+1) * PAGE_SIZE, PAGE_SIZE)
  218. if string == None:
  219. return -1
  220. for i in range(0, len(string)):
  221. temp = struct.unpack_from("B", string, i)[0]
  222. if (self.internal_compare(temp, 0xcc)) != 0:
  223. if peak_stack_used < (self.stack_size - (page_index+1) * PAGE_SIZE - i):
  224. peak_stack_used = self.stack_size- (page_index+1) * PAGE_SIZE - i
  225. break # go to the top for loop
  226. return peak_stack_used
  227. def show_emmt(self):
  228. ret = gdb.execute("show sgx_emmt", False, True)
  229. if ret.strip() == "sgx_emmt enabled":
  230. print ("Enclave: \"{0:s}\"".format(self.enclave_path))
  231. peak_stack_used = self.get_peak_stack_used()
  232. if peak_stack_used == -1:
  233. print ("Failed to collect the stack usage information for \"{0:s}\"".format(self.enclave_path))
  234. else:
  235. peak_stack_used_align = (peak_stack_used + KB_SIZE - 1) & ~(KB_SIZE - 1)
  236. print (" [Peak stack used]: {0:d} KB".format(peak_stack_used_align >> 10))
  237. peak_heap_used = self.get_peak_heap_used()
  238. if peak_heap_used == -1:
  239. print ("Failed to collect the heap usage information for \"{0:s}\"".format(self.enclave_path))
  240. elif peak_heap_used == -2:
  241. 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.")
  242. else:
  243. peak_heap_used_align = (peak_heap_used + KB_SIZE - 1) & ~(KB_SIZE - 1)
  244. print (" [Peak heap used]: {0:d} KB".format(peak_heap_used_align >> 10))
  245. def fini_enclave_debug(self):
  246. # If it is HW product enclave, nothing to do
  247. if (self.enclave_type & ET_SIM) != ET_SIM and (self.enclave_type & ET_DEBUG) != ET_DEBUG:
  248. return -2
  249. self.show_emmt()
  250. try:
  251. # clear TCS debug flag
  252. for tcs_addr in self.tcs_addr_list:
  253. string = read_from_memory(tcs_addr + 8, 4)
  254. if string == None:
  255. return -2
  256. flag = struct.unpack('I', string)[0]
  257. flag &= (~1)
  258. gdb_cmd = "set *(unsigned int *)%#x = %#x" %(tcs_addr + 8, flag)
  259. gdb.execute(gdb_cmd, False, True)
  260. #unload symbol
  261. if os.path.exists(self.enclave_path) == True:
  262. enclave_path = self.enclave_path
  263. else:
  264. enclave_path = target_path_to_host_path(self.enclave_path)
  265. gdb_cmd = load_symbol_cmd.GetUnloadSymbolCommand(enclave_path, str(self.start_addr))
  266. if gdb_cmd == -1:
  267. return -1
  268. print (gdb_cmd)
  269. try:
  270. gdb.execute(gdb_cmd, False, True)
  271. global ENCLAVES_ADDR
  272. del ENCLAVES_ADDR[self.start_addr]
  273. except gdb.error:
  274. print ("Old gdb doesn't support remove-file-symbol command")
  275. return 0
  276. ##It is possible enclave has been destroyed, so may raise exception on memory access
  277. except gdb.MemoryError:
  278. return -1
  279. except:
  280. return -1
  281. def retrieve_enclave_info(info_addr = 0):
  282. """retrieve one enclave info"""
  283. # Step 1: find the enclave info address
  284. if info_addr == 0:
  285. if SIZE == 4:
  286. info_addr = gdb.parse_and_eval("$eax")
  287. elif SIZE == 8:
  288. info_addr = gdb.parse_and_eval("$rdi")
  289. # Step 2: retrieve the enclave info
  290. info_str = read_from_memory(info_addr, ENCLAVE_INFO_SIZE)
  291. if info_str == None:
  292. return None
  293. info_tuple = struct.unpack_from(INFO_FMT, info_str, 0)
  294. # (next_enclave_info,start_addr,tcs_list,enclave_type,file_name_size,
  295. # lpFileName,g_peak_heap_used_addr)
  296. #print "next_addr: %#x, start_addr: %#x, tcs_list: %#x, enclave_type:%#x, file_name_size: %#x," \
  297. # % (info_tuple[0], info_tuple[1], info_tuple[2], info_tuple[3], info_tuple[4])
  298. #print "name_addr: %#x, peak_heap_used_addr: %#x" \
  299. # % (info_tuple[5], info_tuple[6])
  300. #get enclave path
  301. name_str = read_from_memory(info_tuple[5], info_tuple[4])
  302. if name_str == None:
  303. return None
  304. fmt = str(info_tuple[4]) + 's'
  305. enclave_path = struct.unpack_from(fmt, name_str)[0].decode(encoding='UTF-8')
  306. # get the stack addr list
  307. stack_addr_list = []
  308. tcs_addr_list = []
  309. if SIZE == 4:
  310. fmt = '3I'
  311. elif SIZE == 8:
  312. fmt = '3Q'
  313. tcs_info_addr = info_tuple[2]
  314. if tcs_info_addr == 0:
  315. print ("Error: tcs info address = {0:x}".format(tcs_info_addr))
  316. return None
  317. stacksize = 0;
  318. while tcs_info_addr is not 0:
  319. tcs_info_str = read_from_memory(tcs_info_addr, 3*SIZE)
  320. if tcs_info_str == None:
  321. return None
  322. tcs_info_tuple = struct.unpack_from(fmt, tcs_info_str)
  323. #get tcs struct data
  324. tcs_t_str = read_from_memory(tcs_info_tuple[1], ENCLAVE_TCS_INFO_SIZE)
  325. if tcs_t_str == None:
  326. return None
  327. tcs_t_tuple = struct.unpack_from(TCS_INFO_FMT, tcs_t_str)
  328. if SIZE == 4:
  329. td_fmt = '4I'
  330. elif SIZE == 8:
  331. td_fmt = '4Q'
  332. #get thread_data_t address
  333. td_addr = tcs_t_tuple[7] + info_tuple[1] #thread_data_t = tcs.of_base + debug_enclave_info.start_addr
  334. td_str = read_from_memory(td_addr, (4*SIZE))
  335. if td_str == None:
  336. return None
  337. td_tuple = struct.unpack_from(td_fmt, td_str)
  338. #print ("thread_info:%#x, last_sp:%#x, stack_base_addr:%#x, stack_limit_addr:%#x" \
  339. # % (td_tuple[0], td_tuple[1], td_tuple[2], td_tuple[3]));
  340. if td_tuple[2] != td_tuple[3]:
  341. #stack size = ROUND_TO_PAGE(stack_base_addr - stack_limit_addr) since we have
  342. #a static stack whose size is smaller than PAGE_SIZE
  343. stacksize = (td_tuple[2] - td_tuple[3] + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)
  344. stack_addr_list.append(td_tuple[3]) #use stack limit addr as stack base address
  345. tcs_addr_list.append(tcs_info_tuple[1])
  346. tcs_info_addr = tcs_info_tuple[0]
  347. last_ocall_frame = tcs_info_tuple[2]
  348. last_frame = last_ocall_frame
  349. #print ("last_ocall_frame = {0:x}".format(last_ocall_frame))
  350. while last_ocall_frame is not 0:
  351. if SIZE == 4:
  352. of_fmt = '4I'
  353. elif SIZE == 8:
  354. of_fmt = '4Q'
  355. ocall_frame = read_from_memory(last_ocall_frame, 4*SIZE)
  356. if ocall_frame == None:
  357. return None
  358. ocall_frame_tuple = struct.unpack_from(of_fmt, ocall_frame)
  359. last_frame = ocall_frame_tuple[0]
  360. last_trusted_ocall_frame = td_tuple[1]
  361. #print ("last_trusted_ocall_frame = {0:x}".format(last_trusted_ocall_frame))
  362. #print ("td_tuple[2] = {0:x}".format(td_tuple[2]))
  363. #break
  364. while last_trusted_ocall_frame != td_tuple[2]:
  365. if SIZE == 4:
  366. oc_fmt = '20I'
  367. elif SIZE == 8:
  368. oc_fmt = '20Q'
  369. oc_str = read_from_memory(last_trusted_ocall_frame, 20*SIZE)
  370. if oc_str == None:
  371. return None
  372. oc_tuple = struct.unpack_from(oc_fmt, oc_str)
  373. last_trusted_ocall_frame = oc_tuple[6]
  374. #print ("last_trusted_ocall_frame = {0:x}".format(last_trusted_ocall_frame))
  375. #print ("ocall_frame_tuple[1] = {0:x}".format(ocall_frame_tuple[1]))
  376. #print ("oc_tuple[18] = {0:x}".format(oc_tuple[18]))
  377. #break
  378. if ocall_frame_tuple[1] == oc_tuple[18]:
  379. #ocall_frame.pre_last_frame = 0
  380. #ocall_frame.ret = ocall_context.ocall_ret
  381. #ocall_frame.xbp = ocall_context.xbp
  382. gdb_cmd = "set *(uintptr_t *)%#x = 0" %(last_ocall_frame)
  383. gdb.execute(gdb_cmd, False, True)
  384. gdb_cmd = "set *(uintptr_t *)%#x = %#x" %(last_ocall_frame+(2*SIZE), oc_tuple[11])
  385. gdb.execute(gdb_cmd, False, True)
  386. gdb_cmd = "set *(uintptr_t *)%#x = %#x" %(last_ocall_frame+(3*SIZE), oc_tuple[19])
  387. gdb.execute(gdb_cmd, False, True)
  388. break
  389. last_ocall_frame = last_frame
  390. node = enclave_info(info_tuple[0], info_tuple[1], info_tuple[3], stack_addr_list, \
  391. stacksize, enclave_path, info_tuple[6], tcs_addr_list)
  392. return node
  393. def handle_load_event():
  394. """Handle the enclave loading event.
  395. Firstly, retrieve the enclave info node from register
  396. """
  397. node = retrieve_enclave_info()
  398. if node != None:
  399. node.init_enclave_debug()
  400. else:
  401. return
  402. def handle_unload_event():
  403. node = retrieve_enclave_info()
  404. if node != None:
  405. node.fini_enclave_debug()
  406. else:
  407. return
  408. def is_bp_in_urts():
  409. try:
  410. ip = gdb.parse_and_eval("$pc")
  411. solib_name = gdb.solib_name(int(str(ip).split()[0], 16))
  412. 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):
  413. return False
  414. else:
  415. return True
  416. #If exception happens, just assume it is bp in uRTS.
  417. except:
  418. return True
  419. def init_enclaves_debug():
  420. #execute "set displaced-stepping off" to workaround the gdb 7.11 issue
  421. gdb.execute("set displaced-stepping off", False, True)
  422. enclave_info_addr = gdb.parse_and_eval("*(void**)&g_debug_enclave_info_list")
  423. while enclave_info_addr != 0:
  424. node = retrieve_enclave_info(enclave_info_addr)
  425. if node != None:
  426. node.init_enclave_debug()
  427. else:
  428. return
  429. enclave_info_addr = node.next_ei
  430. return
  431. class detach_enclaves (gdb.Command):
  432. def __init__ (self):
  433. gdb.Command.__init__ (self, "detach_enclaves", gdb.COMMAND_NONE)
  434. def invoke (self, arg, from_tty):
  435. #We reject the command from the input of terminal
  436. if from_tty == True:
  437. return
  438. try:
  439. enclave_info_addr = gdb.parse_and_eval("*(void**)&g_debug_enclave_info_list")
  440. except:
  441. return
  442. while enclave_info_addr != 0:
  443. node = retrieve_enclave_info(enclave_info_addr)
  444. if node != None:
  445. node.fini_enclave_debug()
  446. else:
  447. return
  448. enclave_info_addr = node.next_ei
  449. class UpdateOcallFrame(gdb.Breakpoint):
  450. def __init__(self):
  451. gdb.Breakpoint.__init__ (self, spec="notify_gdb_to_update", internal=1)
  452. def stop(self):
  453. bp_in_urts = is_bp_in_urts()
  454. if bp_in_urts == True:
  455. if SIZE == 4:
  456. base_addr = gdb.parse_and_eval("$eax")
  457. tcs_addr = gdb.parse_and_eval("$edx")
  458. ocall_frame = gdb.parse_and_eval("$ecx")
  459. elif SIZE == 8:
  460. base_addr = gdb.parse_and_eval("$rdi")
  461. tcs_addr = gdb.parse_and_eval("$rsi")
  462. ocall_frame = gdb.parse_and_eval("$rdx")
  463. #print ("base_addr = {0:x}".format(int(base_addr)))
  464. #print ("tcs_addr = {0:x}".format(int(tcs_addr)))
  465. #print ("ocall_frame = {0:x}".format(int(ocall_frame)))
  466. tcs_str = read_from_memory(tcs_addr, ENCLAVE_TCS_INFO_SIZE)
  467. if tcs_str == None:
  468. return False
  469. tcs_tuple = struct.unpack_from(TCS_INFO_FMT, tcs_str)
  470. offset = tcs_tuple[7]
  471. if SIZE == 4:
  472. td_fmt = '4I'
  473. elif SIZE == 8:
  474. td_fmt = '4Q'
  475. td_str = read_from_memory(base_addr+offset, (4*SIZE))
  476. if td_str == None:
  477. return False
  478. td_tuple = struct.unpack_from(td_fmt, td_str)
  479. if SIZE == 4:
  480. trusted_of_fmt = '20I'
  481. elif SIZE == 8:
  482. trusted_of_fmt = '20Q'
  483. last_sp = td_tuple[1]
  484. trusted_ocall_frame = read_from_memory(last_sp, (20*SIZE))
  485. if trusted_ocall_frame == None:
  486. return False
  487. trusted_ocall_frame_tuple = struct.unpack_from(trusted_of_fmt, trusted_ocall_frame)
  488. gdb_cmd = "set *(uintptr_t *)%#x = 0" %(int(ocall_frame))
  489. gdb.execute(gdb_cmd, False, True)
  490. gdb_cmd = "set *(uintptr_t *)%#x = %#x" %(int(ocall_frame+(2*SIZE)), trusted_ocall_frame_tuple[11])
  491. gdb.execute(gdb_cmd, False, True)
  492. gdb_cmd = "set *(uintptr_t *)%#x = %#x" %(int(ocall_frame+(3*SIZE)), trusted_ocall_frame_tuple[19])
  493. gdb.execute(gdb_cmd, False, True)
  494. return False
  495. class LoadEventBreakpoint(gdb.Breakpoint):
  496. def __init__(self):
  497. gdb.Breakpoint.__init__ (self, spec="sgx_debug_load_state_add_element", internal=1)
  498. def stop(self):
  499. bp_in_urts = is_bp_in_urts()
  500. if bp_in_urts == True:
  501. handle_load_event()
  502. return False
  503. class UnloadEventBreakpoint(gdb.Breakpoint):
  504. def __init__(self):
  505. gdb.Breakpoint.__init__ (self, spec="sgx_debug_unload_state_remove_element", internal=1)
  506. def stop(self):
  507. bp_in_urts = is_bp_in_urts()
  508. if bp_in_urts == True:
  509. handle_unload_event()
  510. return False
  511. def sgx_debugger_init():
  512. print ("detect urts is loaded, initializing")
  513. global SIZE
  514. SIZE = gdb.parse_and_eval("sizeof(long)")
  515. inited = 0
  516. bps = gdb.breakpoints()
  517. if None != bps:
  518. for bp in bps:
  519. if bp.location == "sgx_debug_load_state_add_element":
  520. inited = 1
  521. break
  522. if inited == 0:
  523. detach_enclaves()
  524. gdb.execute("source gdb_sgx_cmd", False, True)
  525. UpdateOcallFrame()
  526. LoadEventBreakpoint()
  527. UnloadEventBreakpoint()
  528. gdb.events.exited.connect(exit_handler)
  529. init_enclaves_debug()
  530. def exit_handler(event):
  531. # When the inferior exited, remove all enclave symbol
  532. for key in list(ENCLAVES_ADDR.keys()):
  533. gdb.execute("remove-symbol-file -a %s" % (ENCLAVES_ADDR[key]), False, True)
  534. ENCLAVES_ADDR.clear()
  535. def newobj_handler(event):
  536. solib_name = os.path.basename(event.new_objfile.filename)
  537. if solib_name == 'libsgx_urts.so' or solib_name == 'libsgx_urts_sim.so' or solib_name == 'libsgx_aesm_service.so':
  538. sgx_debugger_init()
  539. return
  540. if __name__ == "__main__":
  541. gdb.events.new_objfile.connect(newobj_handler)
  542. sgx_emmt.init_emmt()