VirtualBox

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

Last change on this file since 102792 was 101539, checked in by vboxsync, 13 months ago

DIS,VMM,DBGC,IPRT,++: Some disassembler tweaks and TB disassembly work. bugref:10371 bugref:9898

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