VirtualBox

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

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

IPRT: Fixed segment alignment bug in the mach-o code. bugref:9232

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 15.1 KB
Line 
1/* $Id: tstLdr-3.cpp 74647 2018-10-06 21:29:40Z 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"
234 " link=%RTptr LB %RTptr align=%RTptr fProt=%#x offFile=%RTfoff\n"
235 , g_iSegNo++, pSeg->RVA, pSeg->cbMapped, pSeg->pszName,
236 pSeg->LinkAddress, pSeg->cb, pSeg->Alignment, pSeg->fProt, pSeg->offFile);
237
238 return VINF_SUCCESS;
239}
240
241
242/**
243 * Enumeration callback function used by RTLdrEnumSymbols().
244 *
245 * @returns iprt status code. Failure will stop the enumeration.
246 * @param hLdrMod The loader module handle.
247 * @param pszSymbol Symbol name. NULL if ordinal only.
248 * @param uSymbol Symbol ordinal, ~0 if not used.
249 * @param Value Symbol value.
250 * @param pvUser The user argument specified to RTLdrEnumSymbols().
251 */
252static DECLCALLBACK(int) testEnumSymbol1(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
253{
254 if (hLdrMod != g_hLdrMod || pvUser != NULL)
255 return VERR_INTERNAL_ERROR_3;
256 RTPrintf(" %RTptr %s (%d)\n", Value, pszSymbol, uSymbol);
257 return VINF_SUCCESS;
258}
259
260
261static int testDisasNear(uint64_t uAddr)
262{
263 TESTNEARSYM NearSym;
264 int rc = FindNearSymbol(uAddr, &NearSym);
265 if (RT_FAILURE(rc))
266 return rc;
267
268 RTPrintf("tstLdr-3: Addr=%RTptr\n"
269 "%RTptr %s (%d) - %RTptr %s (%d)\n",
270 NearSym.Addr,
271 NearSym.aSyms[0].Value, NearSym.aSyms[0].szName, NearSym.aSyms[0].uSymbol,
272 NearSym.aSyms[1].Value, NearSym.aSyms[1].szName, NearSym.aSyms[1].uSymbol);
273 if (NearSym.Addr - NearSym.aSyms[0].Value < 0x10000)
274 {
275 DISCPUMODE enmDisCpuMode = g_cBits == 32 ? DISCPUMODE_32BIT : DISCPUMODE_64BIT;
276 uint8_t *pbCode = (uint8_t *)g_pvBits + (NearSym.aSyms[0].Value - g_uLoadAddr);
277 MyDisBlock(enmDisCpuMode, (uintptr_t)pbCode,
278 RT_MAX(NearSym.aSyms[1].Value - NearSym.aSyms[0].Value, 0x20000),
279 NearSym.aSyms[0].Value - (uintptr_t)pbCode,
280 NearSym.aSyms[0].Value,
281 NearSym.Addr);
282 }
283
284 return VINF_SUCCESS;
285}
286
287int main(int argc, char **argv)
288{
289 RTR3InitExe(argc, &argv, 0);
290
291 int rcRet = 0;
292 if (argc <= 2)
293 {
294 RTPrintf("usage: %s <load-addr> <module> [addr1 []]\n", argv[0]);
295 return 1;
296 }
297
298 /*
299 * Module & code bitness (optional).
300 */
301 g_cBits = ARCH_BITS;
302 if (!strcmp(argv[1], "--32"))
303 {
304 g_cBits = 32;
305 argc--;
306 argv++;
307 }
308 else if (!strcmp(argv[1], "--64"))
309 {
310 g_cBits = 64;
311 argc--;
312 argv++;
313 }
314
315 /*
316 * Load the module.
317 */
318 RTERRINFOSTATIC ErrInfo;
319 g_uLoadAddr = (RTUINTPTR)RTStrToUInt64(argv[1]);
320 int rc = RTLdrOpenEx(argv[2], 0, RTLDRARCH_WHATEVER, &g_hLdrMod, RTErrInfoInitStatic(&ErrInfo));
321 if (RT_FAILURE(rc))
322 {
323 RTPrintf("tstLdr-3: Failed to open '%s': %Rra\n", argv[2], rc);
324 if (ErrInfo.szMsg[0])
325 RTPrintf("tstLdr-3: %s\n", ErrInfo.szMsg);
326 return 1;
327 }
328
329 g_pvBits = RTMemAlloc(RTLdrSize(g_hLdrMod));
330 rc = RTLdrGetBits(g_hLdrMod, g_pvBits, g_uLoadAddr, testGetImport, &g_uLoadAddr);
331 if (RT_SUCCESS(rc))
332 {
333 if ( argc == 4
334 && argv[3][0] == '*')
335 {
336 /*
337 * Wildcard address mode.
338 */
339 uint64_t uWild = RTStrToUInt64(&argv[3][1]);
340 uint64_t uIncrements = strchr(argv[3], '/') ? RTStrToUInt64(strchr(argv[3], '/') + 1) : 0x1000;
341 if (!uIncrements)
342 uIncrements = 0x1000;
343 uint64_t uMax = RTLdrSize(g_hLdrMod) + g_uLoadAddr;
344 for (uint64_t uCur = g_uLoadAddr + uWild; uCur < uMax; uCur += uIncrements)
345 testDisasNear(uCur);
346 }
347 else if (argc > 3)
348 {
349 /*
350 * User specified addresses within the module.
351 */
352 for (int i = 3; i < argc; i++)
353 {
354 rc = testDisasNear(RTStrToUInt64(argv[i]));
355 if (RT_FAILURE(rc))
356 rcRet++;
357 }
358 }
359 else
360 {
361 /*
362 * Enumerate symbols.
363 */
364 rc = RTLdrEnumSymbols(g_hLdrMod, RTLDR_ENUM_SYMBOL_FLAGS_ALL, g_pvBits, g_uLoadAddr, testEnumSymbol1, NULL);
365 if (RT_FAILURE(rc))
366 {
367 RTPrintf("tstLdr-3: Failed to enumerate symbols: %Rra\n", rc);
368 rcRet++;
369 }
370
371 /*
372 * Query various properties.
373 */
374 union
375 {
376 char szName[256];
377 uint32_t iImpModule;
378 RTUUID Uuid;
379 } uBuf;
380 rc = RTLdrQueryProp(g_hLdrMod, RTLDRPROP_INTERNAL_NAME, &uBuf, sizeof(uBuf));
381 if (RT_SUCCESS(rc))
382 RTPrintf("tstLdr-3: Internal name: %s\n", uBuf.szName);
383 else if (rc != VERR_NOT_FOUND && rc != VERR_NOT_SUPPORTED)
384 {
385 RTPrintf("tstLdr-3: Internal name: failed - %Rrc\n", rc);
386 rcRet++;
387 }
388
389 uint32_t cImports = 0;
390 rc = RTLdrQueryProp(g_hLdrMod, RTLDRPROP_IMPORT_COUNT, &cImports, sizeof(cImports));
391 if (RT_SUCCESS(rc))
392 {
393 RTPrintf("tstLdr-3: Import count: %u\n", cImports);
394 for (uint32_t i = 0; i < cImports; i++)
395 {
396 uBuf.iImpModule = i;
397 rc = RTLdrQueryProp(g_hLdrMod, RTLDRPROP_IMPORT_MODULE, &uBuf, sizeof(uBuf));
398 if (RT_SUCCESS(rc))
399 RTPrintf("tstLdr-3: Import module #%u: %s\n", i, uBuf.szName);
400 else
401 {
402 RTPrintf("tstLdr-3: Import module #%u: failed - %Rrc\n", i, rc);
403 rcRet++;
404 }
405 }
406 }
407 else if (rc != VERR_NOT_FOUND && rc != VERR_NOT_SUPPORTED)
408 {
409 RTPrintf("tstLdr-3: Import count: failed - %Rrc\n", rc);
410 rcRet++;
411 }
412
413 rc = RTLdrQueryProp(g_hLdrMod, RTLDRPROP_UUID, &uBuf.Uuid, sizeof(uBuf.Uuid));
414 if (RT_SUCCESS(rc))
415 RTPrintf("tstLdr-3: UUID: %RTuuid\n", uBuf.Uuid);
416 else if (rc != VERR_NOT_FOUND && rc != VERR_NOT_SUPPORTED)
417 {
418 RTPrintf("tstLdr-3: UUID: failed - %Rrc\n", rc);
419 rcRet++;
420 }
421
422 /*
423 * Enumerate segments.
424 */
425 RTPrintf("tstLdr-3: Segments:\n");
426 rc = RTLdrEnumSegments(g_hLdrMod, testEnumSegment1, NULL);
427 if (RT_FAILURE(rc))
428 {
429 RTPrintf("tstLdr-3: Failed to enumerate symbols: %Rra\n", rc);
430 rcRet++;
431 }
432 }
433 }
434 else
435 {
436 RTPrintf("tstLdr-3: Failed to get bits for '%s' at %RTptr: %Rra\n", argv[2], g_uLoadAddr, rc);
437 rcRet++;
438 }
439 RTMemFree(g_pvBits);
440 RTLdrClose(g_hLdrMod);
441
442 /*
443 * Test result summary.
444 */
445 if (!rcRet)
446 RTPrintf("tstLdr-3: SUCCESS\n");
447 else
448 RTPrintf("tstLdr-3: FAILURE - %d errors\n", rcRet);
449 return !!rcRet;
450}
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