VirtualBox

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

Last change on this file since 68155 was 65239, checked in by vboxsync, 8 years ago

IPRT: Added RTLdrOpenEx that takes an optional RTERRINFO.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 12.2 KB
Line 
1/* $Id: tstLdr-3.cpp 65239 2017-01-11 10:38:38Z vboxsync $ */
2/** @file
3 * IPRT - Testcase for parts of RTLdr*, manual inspection.
4 */
5
6/*
7 * Copyright (C) 2006-2016 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
228
229/**
230 * Enumeration callback function used by RTLdrEnumSymbols().
231 *
232 * @returns iprt status code. Failure will stop the enumeration.
233 * @param hLdrMod The loader module handle.
234 * @param pszSymbol Symbol name. NULL if ordinal only.
235 * @param uSymbol Symbol ordinal, ~0 if not used.
236 * @param Value Symbol value.
237 * @param pvUser The user argument specified to RTLdrEnumSymbols().
238 */
239static DECLCALLBACK(int) testEnumSymbol1(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
240{
241 RT_NOREF2(hLdrMod, pvUser);
242 RTPrintf(" %RTptr %s (%d)\n", Value, pszSymbol, uSymbol);
243 return VINF_SUCCESS;
244}
245
246
247static int testDisasNear(uint64_t uAddr)
248{
249 TESTNEARSYM NearSym;
250 int rc = FindNearSymbol(uAddr, &NearSym);
251 if (RT_FAILURE(rc))
252 return rc;
253
254 RTPrintf("tstLdr-3: Addr=%RTptr\n"
255 "%RTptr %s (%d) - %RTptr %s (%d)\n",
256 NearSym.Addr,
257 NearSym.aSyms[0].Value, NearSym.aSyms[0].szName, NearSym.aSyms[0].uSymbol,
258 NearSym.aSyms[1].Value, NearSym.aSyms[1].szName, NearSym.aSyms[1].uSymbol);
259 if (NearSym.Addr - NearSym.aSyms[0].Value < 0x10000)
260 {
261 DISCPUMODE enmDisCpuMode = g_cBits == 32 ? DISCPUMODE_32BIT : DISCPUMODE_64BIT;
262 uint8_t *pbCode = (uint8_t *)g_pvBits + (NearSym.aSyms[0].Value - g_uLoadAddr);
263 MyDisBlock(enmDisCpuMode, (uintptr_t)pbCode,
264 RT_MAX(NearSym.aSyms[1].Value - NearSym.aSyms[0].Value, 0x20000),
265 NearSym.aSyms[0].Value - (uintptr_t)pbCode,
266 NearSym.aSyms[0].Value,
267 NearSym.Addr);
268 }
269
270 return VINF_SUCCESS;
271}
272
273int main(int argc, char **argv)
274{
275 RTR3InitExe(argc, &argv, 0);
276
277 int rcRet = 0;
278 if (argc <= 2)
279 {
280 RTPrintf("usage: %s <load-addr> <module> [addr1 []]\n", argv[0]);
281 return 1;
282 }
283
284 /*
285 * Module & code bitness (optional).
286 */
287 g_cBits = ARCH_BITS;
288 if (!strcmp(argv[1], "--32"))
289 {
290 g_cBits = 32;
291 argc--;
292 argv++;
293 }
294 else if (!strcmp(argv[1], "--64"))
295 {
296 g_cBits = 64;
297 argc--;
298 argv++;
299 }
300
301 /*
302 * Load the module.
303 */
304 RTERRINFOSTATIC ErrInfo;
305 g_uLoadAddr = (RTUINTPTR)RTStrToUInt64(argv[1]);
306 int rc = RTLdrOpenEx(argv[2], 0, RTLDRARCH_WHATEVER, &g_hLdrMod, RTErrInfoInitStatic(&ErrInfo));
307 if (RT_FAILURE(rc))
308 {
309 RTPrintf("tstLdr-3: Failed to open '%s': %Rra\n", argv[2], rc);
310 if (ErrInfo.szMsg[0])
311 RTPrintf("tstLdr-3: %s\n", ErrInfo.szMsg);
312 return 1;
313 }
314
315 g_pvBits = RTMemAlloc(RTLdrSize(g_hLdrMod));
316 rc = RTLdrGetBits(g_hLdrMod, g_pvBits, g_uLoadAddr, testGetImport, &g_uLoadAddr);
317 if (RT_SUCCESS(rc))
318 {
319 if ( argc == 4
320 && argv[3][0] == '*')
321 {
322 /*
323 * Wildcard address mode.
324 */
325 uint64_t uWild = RTStrToUInt64(&argv[3][1]);
326 uint64_t uIncrements = strchr(argv[3], '/') ? RTStrToUInt64(strchr(argv[3], '/') + 1) : 0x1000;
327 if (!uIncrements)
328 uIncrements = 0x1000;
329 uint64_t uMax = RTLdrSize(g_hLdrMod) + g_uLoadAddr;
330 for (uint64_t uCur = g_uLoadAddr + uWild; uCur < uMax; uCur += uIncrements)
331 testDisasNear(uCur);
332 }
333 else if (argc > 3)
334 {
335 /*
336 * User specified addresses within the module.
337 */
338 for (int i = 3; i < argc; i++)
339 {
340 rc = testDisasNear(RTStrToUInt64(argv[i]));
341 if (RT_FAILURE(rc))
342 rcRet++;
343 }
344 }
345 else
346 {
347 /*
348 * Enumerate symbols.
349 */
350 rc = RTLdrEnumSymbols(g_hLdrMod, RTLDR_ENUM_SYMBOL_FLAGS_ALL, g_pvBits, g_uLoadAddr, testEnumSymbol1, NULL);
351 if (RT_FAILURE(rc))
352 {
353 RTPrintf("tstLdr-3: Failed to enumerate symbols: %Rra\n", rc);
354 rcRet++;
355 }
356 }
357 }
358 else
359 {
360 RTPrintf("tstLdr-3: Failed to get bits for '%s' at %RTptr: %Rra\n", argv[2], g_uLoadAddr, rc);
361 rcRet++;
362 }
363 RTMemFree(g_pvBits);
364 RTLdrClose(g_hLdrMod);
365
366 /*
367 * Test result summary.
368 */
369 if (!rcRet)
370 RTPrintf("tstLdr-3: SUCCESS\n");
371 else
372 RTPrintf("tstLdr-3: FAILURE - %d errors\n", rcRet);
373 return !!rcRet;
374}
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