1# Copyright (c) 2012 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import re 6import sys 7import xml.etree.ElementTree 8 9import gdb_rsp 10 11 12def GetTargetArch(connection): 13 """Get the CPU architecture of the NaCl application.""" 14 reply = connection.RspRequest('qXfer:features:read:target.xml:0,fff') 15 assert reply[0] == 'l', reply 16 tree = xml.etree.ElementTree.fromstring(reply[1:]) 17 arch_tag = tree.find('architecture') 18 assert arch_tag is not None, reply 19 return arch_tag.text.strip() 20 21 22def ReverseBytes(byte_string): 23 """Reverse bytes in the hex string: '09ab' -> 'ab09'. This converts 24 little-endian number in the hex string to its normal string representation. 25 """ 26 assert len(byte_string) % 2 == 0, byte_string 27 return ''.join([byte_string[i - 2 : i] 28 for i in xrange(len(byte_string), 0, -2)]) 29 30 31def GetProgCtrString(connection, arch): 32 """Get current execution point.""" 33 registers = connection.RspRequest('g') 34 # PC register indices can be found in 35 # native_client/src/trusted/debug_stub/abi.cc in AbiInit function. 36 if arch == 'i386': 37 # eip index is 8 38 return ReverseBytes(registers[8 * 8 : 8 * 8 + 8]) 39 if arch == 'i386:x86-64': 40 # rip index is 16 41 return ReverseBytes(registers[16 * 16 : 16 * 16 + 8]) 42 if arch == 'iwmmxt': 43 # pc index is 15 44 return ReverseBytes(registers[15 * 8 : 15 * 8 + 8]) 45 raise AssertionError('Unknown architecture: %s' % arch) 46 47 48def TestContinue(connection): 49 result = connection.RspRequest('vCont;c') 50 # Once the NaCl test module reports that the test passed, the NaCl <embed> 51 # element is removed from the page and so the NaCl module is killed by 52 # the browser what is reported as exit due to SIGKILL (X09). 53 assert result == 'X09', result 54 55 56def TestBreakpoint(connection): 57 # Breakpoints and single-stepping might interfere with Chrome sandbox. So we 58 # check that they work properly in this test. 59 arch = GetTargetArch(connection) 60 registers = connection.RspRequest('g') 61 pc = GetProgCtrString(connection, arch) 62 # Set breakpoint 63 result = connection.RspRequest('Z0,%s,1' % pc) 64 assert result == 'OK', result 65 # Check that we stopped at breakpoint 66 result = connection.RspRequest('vCont;c') 67 stop_reply = re.compile(r'T05thread:(\d+);') 68 assert stop_reply.match(result), result 69 thread = stop_reply.match(result).group(1) 70 # Check that registers haven't changed 71 result = connection.RspRequest('g') 72 assert result == registers, (result, registers) 73 # Remove breakpoint 74 result = connection.RspRequest('z0,%s,1' % pc) 75 assert result == 'OK', result 76 # Check single stepping 77 result = connection.RspRequest('vCont;s:%s' % thread) 78 assert result == 'T05thread:%s;' % thread, result 79 assert pc != GetProgCtrString(connection, arch) 80 # Check that we terminate normally 81 result = connection.RspRequest('vCont;c') 82 assert result == 'X09', result 83 84 85def Main(args): 86 port = int(args[0]) 87 name = args[1] 88 connection = gdb_rsp.GdbRspConnection(('localhost', port)) 89 if name == 'continue': 90 TestContinue(connection) 91 elif name == 'breakpoint': 92 TestBreakpoint(connection) 93 else: 94 raise AssertionError('Unknown test name: %r' % name) 95 96 97if __name__ == '__main__': 98 Main(sys.argv[1:]) 99