1import lldb 2from lldbsuite.test.lldbtest import * 3from lldbsuite.test.decorators import * 4from lldbsuite.test.gdbclientutils import * 5from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase 6 7 8class MyResponder(MockGDBServerResponder): 9 """ 10 A responder which simulates a process with a single shared library loaded. 11 Its parameters allow configuration of various properties of the library. 12 """ 13 14 def __init__(self, testcase, triple, library_name, auxv_entry, region_info): 15 MockGDBServerResponder.__init__(self) 16 self.testcase = testcase 17 self._triple = triple 18 self._library_name = library_name 19 self._auxv_entry = auxv_entry 20 self._region_info = region_info 21 22 def qSupported(self, client_supported): 23 return ( 24 super().qSupported(client_supported) 25 + ";qXfer:auxv:read+;qXfer:libraries-svr4:read+" 26 ) 27 28 def qXferRead(self, obj, annex, offset, length): 29 if obj == "features" and annex == "target.xml": 30 return ( 31 """<?xml version="1.0"?> 32 <target version="1.0"> 33 <architecture>i386:x86-64</architecture> 34 <feature name="org.gnu.gdb.i386.core"> 35 <reg name="rip" bitsize="64" regnum="0" type="code_ptr" group="general"/> 36 </feature> 37 </target>""", 38 False, 39 ) 40 elif obj == "auxv": 41 # 0x09 = AT_ENTRY, which lldb uses to compute the load bias of the 42 # main binary. 43 return ( 44 hex_decode_bytes( 45 self._auxv_entry 46 + "09000000000000000000ee000000000000000000000000000000000000000000" 47 ), 48 False, 49 ) 50 elif obj == "libraries-svr4": 51 return ( 52 """<?xml version="1.0"?> 53 <library-list-svr4 version="1.0"> 54 <library name="%s" lm="0xdeadbeef" l_addr="0xef0000" l_ld="0xdeadbeef"/> 55 </library-list-svr4>""" 56 % self._library_name, 57 False, 58 ) 59 else: 60 return None, False 61 62 def qfThreadInfo(self): 63 return "m47" 64 65 def qsThreadInfo(self): 66 return "l" 67 68 def qProcessInfo(self): 69 return "pid:47;ptrsize:8;endian:little;triple:%s;" % hex_encode_bytes( 70 self._triple 71 ) 72 73 def setBreakpoint(self, packet): 74 return "OK" 75 76 def readMemory(self, addr, length): 77 if addr == 0xEE1000: 78 return "00" * 0x30 + "0020ee0000000000" 79 elif addr == 0xEE2000: 80 return "01000000000000000030ee0000000000dead00000000000000000000000000000000000000000000" 81 elif addr == 0xEF0000: 82 with open(self.testcase.getBuildArtifact("libmodule_load.so"), "rb") as f: 83 contents = f.read(-1) 84 return hex_encode_bytes(seven.bitcast_to_string(contents)) 85 return ("baadf00d00" * 1000)[0 : length * 2] 86 87 def qMemoryRegionInfo(self, addr): 88 if addr < 0xEE0000: 89 return "start:0;size:ee0000;" 90 elif addr < 0xEF0000: 91 return "start:ee0000;size:10000;" 92 elif addr < 0xF00000: 93 return "start:ef0000;size:1000;permissions:rx;" + self._region_info 94 else: 95 return "start:ef1000;size:ffffffffff10f000" 96 97 98class TestGdbClientModuleLoad(GDBRemoteTestBase): 99 @skipIfXmlSupportMissing 100 def test_android_app_process(self): 101 """ 102 This test simulates the scenario where the (android) dynamic linker 103 reports incorrect file name of the main executable. Lldb uses 104 qMemoryRegionInfo to get the correct value. 105 """ 106 region_info = "name:%s;" % ( 107 hex_encode_bytes(self.getBuildArtifact("libmodule_load.so")) 108 ) 109 self.server.responder = MyResponder( 110 self, "x86_64-pc-linux-android", "bogus-name", "", region_info 111 ) 112 self.yaml2obj("module_load.yaml", self.getBuildArtifact("libmodule_load.so")) 113 target = self.createTarget("module_load.yaml") 114 115 process = self.connect(target) 116 self.assertTrue(process.IsValid(), "Process is valid") 117 118 lldbutil.expect_state_changes( 119 self, self.dbg.GetListener(), process, [lldb.eStateStopped] 120 ) 121 122 self.filecheck("image list", __file__, "-check-prefix=ANDROID") 123 124 # ANDROID: [ 0] {{.*}} 0x0000000000ee0000 {{.*}}module_load 125 # ANDROID: [ 1] {{.*}} 0x0000000000ef0000 {{.*}}libmodule_load.so 126 127 @skipIfXmlSupportMissing 128 def test_vdso(self): 129 """ 130 This test checks vdso loading in the situation where the process does 131 not have memory region information about the vdso address. This can 132 happen in core files, as they don't store this data. 133 We want to check that the vdso is loaded exactly once. 134 """ 135 # vdso address 136 AT_SYSINFO_EHDR = "21000000000000000000ef0000000000" 137 self.server.responder = MyResponder( 138 self, "x86_64-pc-linux", "linux-vdso.so.1", AT_SYSINFO_EHDR, "" 139 ) 140 self.yaml2obj("module_load.yaml", self.getBuildArtifact("libmodule_load.so")) 141 target = self.createTarget("module_load.yaml") 142 143 process = self.connect(target) 144 self.assertTrue(process.IsValid(), "Process is valid") 145 146 lldbutil.expect_state_changes( 147 self, self.dbg.GetListener(), process, [lldb.eStateStopped] 148 ) 149 150 self.filecheck("image list", __file__, "-check-prefix=VDSO") 151 # VDSO: [ 0] {{.*}} 0x0000000000ee0000 {{.*}}module_load 152 # VDSO: [ 1] {{.*}} 0x0000000000ef0000 {{.*}}[vdso] 153 self.assertEqual(self.target().GetNumModules(), 2) 154