VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstLdr-3.cpp@ 74646

Last change on this file since 74646 was 74646, checked in by vboxsync, 6 years ago

IPRT: More adjustments to the LX and Mach-O loader code from kStuff. bugref:9232

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 14.9 KB
Line 
1/* $Id: tstLdr-3.cpp 74646 2018-10-06 21:03:45Z vboxsync $ */
2/** @file
3 * IPRT - Testcase for parts of RTLdr*, manual inspection.
4 */
5
6/*
7 * Copyright (C) 2006-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/ldr.h>
32#include <iprt/alloc.h>
33#include <iprt/stream.h>
34#include <iprt/assert.h>
35#include <iprt/initterm.h>
36#include <iprt/err.h>
37#include <iprt/string.h>
38#include <VBox/dis.h>
39
40
41/*********************************************************************************************************************************
42* Global Variables *
43*********************************************************************************************************************************/
44static RTUINTPTR g_uLoadAddr;
45static RTLDRMOD g_hLdrMod;
46static void *g_pvBits;
47static uint8_t g_cBits;
48
49/**
50 * Current nearest symbol.
51 */
52typedef struct TESTNEARSYM
53{
54 RTUINTPTR Addr;
55 struct TESTSYM
56 {
57 RTUINTPTR Value;
58 unsigned uSymbol;
59 char szName[512];
60 } aSyms[2];
61} TESTNEARSYM, *PTESTNEARSYM;
62
63/**
64 * Enumeration callback function used by RTLdrEnumSymbols().
65 *
66 * @returns iprt status code. Failure will stop the enumeration.
67 * @param hLdrMod The loader module handle.
68 * @param pszSymbol Symbol name. NULL if ordinal only.
69 * @param uSymbol Symbol ordinal, ~0 if not used.
70 * @param Value Symbol value.
71 * @param pvUser The user argument specified to RTLdrEnumSymbols().
72 */
73static DECLCALLBACK(int) testEnumSymbol2(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
74{
75 RT_NOREF1(hLdrMod);
76 PTESTNEARSYM pSym = (PTESTNEARSYM)pvUser;
77
78 /* less or equal */
79 if ( Value <= pSym->Addr
80 && ( Value > pSym->aSyms[0].Value
81 || ( Value == pSym->aSyms[0].Value
82 && !pSym->aSyms[0].szName[0]
83 && pszSymbol
84 && *pszSymbol
85 )
86 )
87 )
88 {
89 pSym->aSyms[0].Value = Value;
90 pSym->aSyms[0].uSymbol = uSymbol;
91 pSym->aSyms[0].szName[0] = '\0';
92 if (pszSymbol)
93 strncat(pSym->aSyms[0].szName, pszSymbol, sizeof(pSym->aSyms[0].szName)-1);
94 }
95
96 /* above */
97 if ( Value > pSym->Addr
98 && ( Value < pSym->aSyms[1].Value
99 || ( Value == pSym->aSyms[1].Value
100 && !pSym->aSyms[1].szName[1]
101 && pszSymbol
102 && *pszSymbol
103 )
104 )
105 )
106 {
107 pSym->aSyms[1].Value = Value;
108 pSym->aSyms[1].uSymbol = uSymbol;
109 pSym->aSyms[1].szName[0] = '\0';
110 if (pszSymbol)
111 strncat(pSym->aSyms[1].szName, pszSymbol, sizeof(pSym->aSyms[1].szName)-1);
112 }
113
114 return VINF_SUCCESS;
115}
116
117static int FindNearSymbol(RTUINTPTR uAddr, PTESTNEARSYM pNearSym)
118{
119 RT_ZERO(*pNearSym);
120 pNearSym->Addr = (RTUINTPTR)uAddr;
121 pNearSym->aSyms[1].Value = ~(RTUINTPTR)0;
122 int rc = RTLdrEnumSymbols(g_hLdrMod, RTLDR_ENUM_SYMBOL_FLAGS_ALL, g_pvBits, g_uLoadAddr, testEnumSymbol2, pNearSym);
123 if (RT_FAILURE(rc))
124 RTPrintf("tstLdr-3: Failed to enumerate symbols: %Rra\n", rc);
125 return rc;
126}
127
128static DECLCALLBACK(int) MyGetSymbol(PCDISCPUSTATE pCpu, uint32_t u32Sel, RTUINTPTR uAddress,
129 char *pszBuf, size_t cchBuf, RTINTPTR *poff,
130 void *pvUser)
131{
132 RT_NOREF3(pCpu, u32Sel, pvUser);
133
134 if ( uAddress > RTLdrSize(g_hLdrMod) + g_uLoadAddr
135 || uAddress < g_uLoadAddr)
136 return VERR_SYMBOL_NOT_FOUND;
137
138 TESTNEARSYM NearSym;
139 int rc = FindNearSymbol(uAddress, &NearSym);
140 if (RT_FAILURE(rc))
141 return rc;
142
143 RTStrCopy(pszBuf, cchBuf, NearSym.aSyms[0].szName);
144 *poff = uAddress - NearSym.aSyms[0].Value;
145 return VINF_SUCCESS;
146}
147
148
149/**
150 * @callback_method_impl{FNDISREADBYTES}
151 */
152static DECLCALLBACK(int) MyReadBytes(PDISCPUSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
153{
154 RT_NOREF1(cbMaxRead);
155 uint8_t const *pbSrc = (uint8_t const *)((uintptr_t)pDis->uInstrAddr + (uintptr_t)pDis->pvUser + offInstr);
156 memcpy(&pDis->abInstr[offInstr], pbSrc, cbMinRead);
157 pDis->cbCachedInstr = offInstr + cbMinRead;
158 return VINF_SUCCESS;
159}
160
161
162static bool MyDisBlock(DISCPUMODE enmCpuMode, RTHCUINTPTR pvCodeBlock, int32_t cbMax, RTUINTPTR off,
163 RTUINTPTR uNearAddr, RTUINTPTR uSearchAddr)
164{
165 DISCPUSTATE Cpu;
166 int32_t i = 0;
167 while (i < cbMax)
168 {
169 bool fQuiet = RTAssertSetQuiet(true);
170 bool fMayPanic = RTAssertSetMayPanic(false);
171 char szOutput[256];
172 unsigned cbInstr;
173 int rc = DISInstrWithReader(uNearAddr + i, enmCpuMode,
174 MyReadBytes, (uint8_t *)pvCodeBlock - (uintptr_t)uNearAddr,
175 &Cpu, &cbInstr);
176 RTAssertSetMayPanic(fMayPanic);
177 RTAssertSetQuiet(fQuiet);
178 if (RT_FAILURE(rc))
179 return false;
180
181 TESTNEARSYM NearSym;
182 rc = FindNearSymbol(uNearAddr + i, &NearSym);
183 if (RT_SUCCESS(rc) && NearSym.aSyms[0].Value == NearSym.Addr)
184 RTPrintf("%s:\n", NearSym.aSyms[0].szName);
185
186 DISFormatYasmEx(&Cpu, szOutput, sizeof(szOutput),
187 DIS_FMT_FLAGS_RELATIVE_BRANCH | DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_ADDR_LEFT | DIS_FMT_FLAGS_BYTES_SPACED,
188 MyGetSymbol, NULL);
189
190 RTPrintf("%s\n", szOutput);
191 if (pvCodeBlock + i + off == uSearchAddr)
192 RTPrintf("^^^^^^^^\n");
193
194 /* next */
195 i += cbInstr;
196 }
197 return true;
198}
199
200
201
202/**
203 * Resolve an external symbol during RTLdrGetBits().
204 *
205 * @returns iprt status code.
206 * @param hLdrMod The loader module handle.
207 * @param pszModule Module name.
208 * @param pszSymbol Symbol name, NULL if uSymbol should be used.
209 * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
210 * @param pValue Where to store the symbol value (address).
211 * @param pvUser User argument.
212 */
213static DECLCALLBACK(int) testGetImport(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol,
214 unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
215{
216 RT_NOREF5(hLdrMod, pszModule, pszSymbol, uSymbol, pvUser);
217#if 1
218 RTUINTPTR BaseAddr = *(PCRTUINTPTR)pvUser;
219 *pValue = BaseAddr + UINT32_C(0x604020f0);
220#else
221 *pValue = UINT64_C(0xffffff7f820df000);
222#endif
223 if (g_cBits == 32)
224 *pValue &= UINT32_MAX;
225 return VINF_SUCCESS;
226}
227
228static uint32_t g_iSegNo = 0;
229static DECLCALLBACK(int) testEnumSegment1(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
230{
231 if (hLdrMod != g_hLdrMod || pvUser != NULL)
232 return VERR_INTERNAL_ERROR_3;
233 RTPrintf("Seg#%02u: %RTptr LB %RTptr %s\n", g_iSegNo++, pSeg->RVA, pSeg->cbMapped, pSeg->pszName);
234
235 return VINF_SUCCESS;
236}
237
238
239/**
240 * Enumeration callback function used by RTLdrEnumSymbols().
241 *
242 * @returns iprt status code. Failure will stop the enumeration.
243 * @param hLdrMod The loader module handle.
244 * @param pszSymbol Symbol name. NULL if ordinal only.
245 * @param uSymbol Symbol ordinal, ~0 if not used.
246 * @param Value Symbol value.
247 * @param pvUser The user argument specified to RTLdrEnumSymbols().
248 */
249static DECLCALLBACK(int) testEnumSymbol1(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
250{
251 if (hLdrMod != g_hLdrMod || pvUser != NULL)
252 return VERR_INTERNAL_ERROR_3;
253 RTPrintf(" %RTptr %s (%d)\n", Value, pszSymbol, uSymbol);
254 return VINF_SUCCESS;
255}
256
257
258static int testDisasNear(uint64_t uAddr)
259{
260 TESTNEARSYM NearSym;
261 int rc = FindNearSymbol(uAddr, &NearSym);
262 if (RT_FAILURE(rc))
263 return rc;
264
265 RTPrintf("tstLdr-3: Addr=%RTptr\n"
266 "%RTptr %s (%d) - %RTptr %s (%d)\n",
267 NearSym.Addr,
268 NearSym.aSyms[0].Value, NearSym.aSyms[0].szName, NearSym.aSyms[0].uSymbol,
269 NearSym.aSyms[1].Value, NearSym.aSyms[1].szName, NearSym.aSyms[1].uSymbol);
270 if (NearSym.Addr - NearSym.aSyms[0].Value < 0x10000)
271 {
272 DISCPUMODE enmDisCpuMode = g_cBits == 32 ? DISCPUMODE_32BIT : DISCPUMODE_64BIT;
273 uint8_t *pbCode = (uint8_t *)g_pvBits + (NearSym.aSyms[0].Value - g_uLoadAddr);
274 MyDisBlock(enmDisCpuMode, (uintptr_t)pbCode,
275 RT_MAX(NearSym.aSyms[1].Value - NearSym.aSyms[0].Value, 0x20000),
276 NearSym.aSyms[0].Value - (uintptr_t)pbCode,
277 NearSym.aSyms[0].Value,
278 NearSym.Addr);
279 }
280
281 return VINF_SUCCESS;
282}
283
284int main(int argc, char **argv)
285{
286 RTR3InitExe(argc, &argv, 0);
287
288 int rcRet = 0;
289 if (argc <= 2)
290 {
291 RTPrintf("usage: %s <load-addr> <module> [addr1 []]\n", argv[0]);
292 return 1;
293 }
294
295 /*
296 * Module & code bitness (optional).
297 */
298 g_cBits = ARCH_BITS;
299 if (!strcmp(argv[1], "--32"))
300 {
301 g_cBits = 32;
302 argc--;
303 argv++;
304 }
305 else if (!strcmp(argv[1], "--64"))
306 {
307 g_cBits = 64;
308 argc--;
309 argv++;
310 }
311
312 /*
313 * Load the module.
314 */
315 RTERRINFOSTATIC ErrInfo;
316 g_uLoadAddr = (RTUINTPTR)RTStrToUInt64(argv[1]);
317 int rc = RTLdrOpenEx(argv[2], 0, RTLDRARCH_WHATEVER, &g_hLdrMod, RTErrInfoInitStatic(&ErrInfo));
318 if (RT_FAILURE(rc))
319 {
320 RTPrintf("tstLdr-3: Failed to open '%s': %Rra\n", argv[2], rc);
321 if (ErrInfo.szMsg[0])
322 RTPrintf("tstLdr-3: %s\n", ErrInfo.szMsg);
323 return 1;
324 }
325
326 g_pvBits = RTMemAlloc(RTLdrSize(g_hLdrMod));
327 rc = RTLdrGetBits(g_hLdrMod, g_pvBits, g_uLoadAddr, testGetImport, &g_uLoadAddr);
328 if (RT_SUCCESS(rc))
329 {
330 if ( argc == 4
331 && argv[3][0] == '*')
332 {
333 /*
334 * Wildcard address mode.
335 */
336 uint64_t uWild = RTStrToUInt64(&argv[3][1]);
337 uint64_t uIncrements = strchr(argv[3], '/') ? RTStrToUInt64(strchr(argv[3], '/') + 1) : 0x1000;
338 if (!uIncrements)
339 uIncrements = 0x1000;
340 uint64_t uMax = RTLdrSize(g_hLdrMod) + g_uLoadAddr;
341 for (uint64_t uCur = g_uLoadAddr + uWild; uCur < uMax; uCur += uIncrements)
342 testDisasNear(uCur);
343 }
344 else if (argc > 3)
345 {
346 /*
347 * User specified addresses within the module.
348 */
349 for (int i = 3; i < argc; i++)
350 {
351 rc = testDisasNear(RTStrToUInt64(argv[i]));
352 if (RT_FAILURE(rc))
353 rcRet++;
354 }
355 }
356 else
357 {
358 /*
359 * Enumerate symbols.
360 */
361 rc = RTLdrEnumSymbols(g_hLdrMod, RTLDR_ENUM_SYMBOL_FLAGS_ALL, g_pvBits, g_uLoadAddr, testEnumSymbol1, NULL);
362 if (RT_FAILURE(rc))
363 {
364 RTPrintf("tstLdr-3: Failed to enumerate symbols: %Rra\n", rc);
365 rcRet++;
366 }
367
368 /*
369 * Query various properties.
370 */
371 union
372 {
373 char szName[256];
374 uint32_t iImpModule;
375 RTUUID Uuid;
376 } uBuf;
377 rc = RTLdrQueryProp(g_hLdrMod, RTLDRPROP_INTERNAL_NAME, &uBuf, sizeof(uBuf));
378 if (RT_SUCCESS(rc))
379 RTPrintf("tstLdr-3: Internal name: %s\n", uBuf.szName);
380 else if (rc != VERR_NOT_FOUND && rc != VERR_NOT_SUPPORTED)
381 {
382 RTPrintf("tstLdr-3: Internal name: failed - %Rrc\n", rc);
383 rcRet++;
384 }
385
386 uint32_t cImports = 0;
387 rc = RTLdrQueryProp(g_hLdrMod, RTLDRPROP_IMPORT_COUNT, &cImports, sizeof(cImports));
388 if (RT_SUCCESS(rc))
389 {
390 RTPrintf("tstLdr-3: Import count: %u\n", cImports);
391 for (uint32_t i = 0; i < cImports; i++)
392 {
393 uBuf.iImpModule = i;
394 rc = RTLdrQueryProp(g_hLdrMod, RTLDRPROP_IMPORT_MODULE, &uBuf, sizeof(uBuf));
395 if (RT_SUCCESS(rc))
396 RTPrintf("tstLdr-3: Import module #%u: %s\n", i, uBuf.szName);
397 else
398 {
399 RTPrintf("tstLdr-3: Import module #%u: failed - %Rrc\n", i, rc);
400 rcRet++;
401 }
402 }
403 }
404 else if (rc != VERR_NOT_FOUND && rc != VERR_NOT_SUPPORTED)
405 {
406 RTPrintf("tstLdr-3: Import count: failed - %Rrc\n", rc);
407 rcRet++;
408 }
409
410 rc = RTLdrQueryProp(g_hLdrMod, RTLDRPROP_UUID, &uBuf.Uuid, sizeof(uBuf.Uuid));
411 if (RT_SUCCESS(rc))
412 RTPrintf("tstLdr-3: UUID: %RTuuid\n", uBuf.Uuid);
413 else if (rc != VERR_NOT_FOUND && rc != VERR_NOT_SUPPORTED)
414 {
415 RTPrintf("tstLdr-3: UUID: failed - %Rrc\n", rc);
416 rcRet++;
417 }
418
419 /*
420 * Enumerate segments.
421 */
422 RTPrintf("tstLdr-3: Segments:\n");
423 rc = RTLdrEnumSegments(g_hLdrMod, testEnumSegment1, NULL);
424 if (RT_FAILURE(rc))
425 {
426 RTPrintf("tstLdr-3: Failed to enumerate symbols: %Rra\n", rc);
427 rcRet++;
428 }
429 }
430 }
431 else
432 {
433 RTPrintf("tstLdr-3: Failed to get bits for '%s' at %RTptr: %Rra\n", argv[2], g_uLoadAddr, rc);
434 rcRet++;
435 }
436 RTMemFree(g_pvBits);
437 RTLdrClose(g_hLdrMod);
438
439 /*
440 * Test result summary.
441 */
442 if (!rcRet)
443 RTPrintf("tstLdr-3: SUCCESS\n");
444 else
445 RTPrintf("tstLdr-3: FAILURE - %d errors\n", rcRet);
446 return !!rcRet;
447}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette