VirtualBox

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

Last change on this file since 95841 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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