VirtualBox

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

Last change on this file since 61730 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 11.9 KB
Line 
1/* $Id: tstLdr-3.cpp 57358 2015-08-14 15:16:38Z vboxsync $ */
2/** @file
3 * IPRT - Testcase for parts of RTLdr*, manual inspection.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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 PTESTNEARSYM pSym = (PTESTNEARSYM)pvUser;
76
77 /* less or equal */
78 if ( Value <= pSym->Addr
79 && ( Value > pSym->aSyms[0].Value
80 || ( Value == pSym->aSyms[0].Value
81 && !pSym->aSyms[0].szName[0]
82 && pszSymbol
83 && *pszSymbol
84 )
85 )
86 )
87 {
88 pSym->aSyms[0].Value = Value;
89 pSym->aSyms[0].uSymbol = uSymbol;
90 pSym->aSyms[0].szName[0] = '\0';
91 if (pszSymbol)
92 strncat(pSym->aSyms[0].szName, pszSymbol, sizeof(pSym->aSyms[0].szName)-1);
93 }
94
95 /* above */
96 if ( Value > pSym->Addr
97 && ( Value < pSym->aSyms[1].Value
98 || ( Value == pSym->aSyms[1].Value
99 && !pSym->aSyms[1].szName[1]
100 && pszSymbol
101 && *pszSymbol
102 )
103 )
104 )
105 {
106 pSym->aSyms[1].Value = Value;
107 pSym->aSyms[1].uSymbol = uSymbol;
108 pSym->aSyms[1].szName[0] = '\0';
109 if (pszSymbol)
110 strncat(pSym->aSyms[1].szName, pszSymbol, sizeof(pSym->aSyms[1].szName)-1);
111 }
112
113 return VINF_SUCCESS;
114}
115
116static int FindNearSymbol(RTUINTPTR uAddr, PTESTNEARSYM pNearSym)
117{
118 RT_ZERO(*pNearSym);
119 pNearSym->Addr = (RTUINTPTR)uAddr;
120 pNearSym->aSyms[1].Value = ~(RTUINTPTR)0;
121 int rc = RTLdrEnumSymbols(g_hLdrMod, RTLDR_ENUM_SYMBOL_FLAGS_ALL, g_pvBits, g_uLoadAddr, testEnumSymbol2, pNearSym);
122 if (RT_FAILURE(rc))
123 RTPrintf("tstLdr-3: Failed to enumerate symbols: %Rra\n", rc);
124 return rc;
125}
126
127static DECLCALLBACK(int) MyGetSymbol(PCDISCPUSTATE pCpu, uint32_t u32Sel, RTUINTPTR uAddress,
128 char *pszBuf, size_t cchBuf, RTINTPTR *poff,
129 void *pvUser)
130{
131 if ( uAddress > RTLdrSize(g_hLdrMod) + g_uLoadAddr
132 || uAddress < g_uLoadAddr)
133 return VERR_SYMBOL_NOT_FOUND;
134
135 TESTNEARSYM NearSym;
136 int rc = FindNearSymbol(uAddress, &NearSym);
137 if (RT_FAILURE(rc))
138 return rc;
139
140 RTStrCopy(pszBuf, cchBuf, NearSym.aSyms[0].szName);
141 *poff = uAddress - NearSym.aSyms[0].Value;
142 return VINF_SUCCESS;
143}
144
145
146/**
147 * @callback_method_impl{FNDISREADBYTES}
148 */
149static DECLCALLBACK(int) MyReadBytes(PDISCPUSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
150{
151 uint8_t const *pbSrc = (uint8_t const *)((uintptr_t)pDis->uInstrAddr + (uintptr_t)pDis->pvUser + offInstr);
152 memcpy(&pDis->abInstr[offInstr], pbSrc, cbMinRead);
153 pDis->cbCachedInstr = offInstr + cbMinRead;
154 return VINF_SUCCESS;
155}
156
157
158static bool MyDisBlock(DISCPUMODE enmCpuMode, RTHCUINTPTR pvCodeBlock, int32_t cbMax, RTUINTPTR off,
159 RTUINTPTR uNearAddr, RTUINTPTR uSearchAddr)
160{
161 DISCPUSTATE Cpu;
162 int32_t i = 0;
163 while (i < cbMax)
164 {
165 bool fQuiet = RTAssertSetQuiet(true);
166 bool fMayPanic = RTAssertSetMayPanic(false);
167 char szOutput[256];
168 unsigned cbInstr;
169 int rc = DISInstrWithReader(uNearAddr + i, enmCpuMode,
170 MyReadBytes, (uint8_t *)pvCodeBlock - (uintptr_t)uNearAddr,
171 &Cpu, &cbInstr);
172 RTAssertSetMayPanic(fMayPanic);
173 RTAssertSetQuiet(fQuiet);
174 if (RT_FAILURE(rc))
175 return false;
176
177 TESTNEARSYM NearSym;
178 rc = FindNearSymbol(uNearAddr + i, &NearSym);
179 if (RT_SUCCESS(rc) && NearSym.aSyms[0].Value == NearSym.Addr)
180 RTPrintf("%s:\n", NearSym.aSyms[0].szName);
181
182 DISFormatYasmEx(&Cpu, szOutput, sizeof(szOutput),
183 DIS_FMT_FLAGS_RELATIVE_BRANCH | DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_ADDR_LEFT | DIS_FMT_FLAGS_BYTES_SPACED,
184 MyGetSymbol, NULL);
185
186 RTPrintf("%s\n", szOutput);
187 if (pvCodeBlock + i + off == uSearchAddr)
188 RTPrintf("^^^^^^^^\n");
189
190 /* next */
191 i += cbInstr;
192 }
193 return true;
194}
195
196
197
198/**
199 * Resolve an external symbol during RTLdrGetBits().
200 *
201 * @returns iprt status code.
202 * @param hLdrMod The loader module handle.
203 * @param pszModule Module name.
204 * @param pszSymbol Symbol name, NULL if uSymbol should be used.
205 * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
206 * @param pValue Where to store the symbol value (address).
207 * @param pvUser User argument.
208 */
209static DECLCALLBACK(int) testGetImport(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
210{
211#if 1
212 RTUINTPTR BaseAddr = *(PCRTUINTPTR)pvUser;
213 *pValue = BaseAddr + UINT32_C(0x604020f0);
214#else
215 *pValue = UINT64_C(0xffffff7f820df000);
216#endif
217 if (g_cBits == 32)
218 *pValue &= UINT32_MAX;
219 return VINF_SUCCESS;
220}
221
222
223/**
224 * Enumeration callback function used by RTLdrEnumSymbols().
225 *
226 * @returns iprt status code. Failure will stop the enumeration.
227 * @param hLdrMod The loader module handle.
228 * @param pszSymbol Symbol name. NULL if ordinal only.
229 * @param uSymbol Symbol ordinal, ~0 if not used.
230 * @param Value Symbol value.
231 * @param pvUser The user argument specified to RTLdrEnumSymbols().
232 */
233static DECLCALLBACK(int) testEnumSymbol1(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
234{
235 RTPrintf(" %RTptr %s (%d)\n", Value, pszSymbol, uSymbol);
236 return VINF_SUCCESS;
237}
238
239
240static int testDisasNear(uint64_t uAddr)
241{
242 TESTNEARSYM NearSym;
243 int rc = FindNearSymbol(uAddr, &NearSym);
244 if (RT_FAILURE(rc))
245 return rc;
246
247 RTPrintf("tstLdr-3: Addr=%RTptr\n"
248 "%RTptr %s (%d) - %RTptr %s (%d)\n",
249 NearSym.Addr,
250 NearSym.aSyms[0].Value, NearSym.aSyms[0].szName, NearSym.aSyms[0].uSymbol,
251 NearSym.aSyms[1].Value, NearSym.aSyms[1].szName, NearSym.aSyms[1].uSymbol);
252 if (NearSym.Addr - NearSym.aSyms[0].Value < 0x10000)
253 {
254 DISCPUMODE enmDisCpuMode = g_cBits == 32 ? DISCPUMODE_32BIT : DISCPUMODE_64BIT;
255 uint8_t *pbCode = (uint8_t *)g_pvBits + (NearSym.aSyms[0].Value - g_uLoadAddr);
256 MyDisBlock(enmDisCpuMode, (uintptr_t)pbCode,
257 RT_MAX(NearSym.aSyms[1].Value - NearSym.aSyms[0].Value, 0x20000),
258 NearSym.aSyms[0].Value - (RTUINTPTR)pbCode,
259 NearSym.aSyms[0].Value,
260 NearSym.Addr);
261 }
262
263 return VINF_SUCCESS;
264}
265
266int main(int argc, char **argv)
267{
268 RTR3InitExe(argc, &argv, 0);
269
270 int rcRet = 0;
271 if (argc <= 2)
272 {
273 RTPrintf("usage: %s <load-addr> <module> [addr1 []]\n", argv[0]);
274 return 1;
275 }
276
277 /*
278 * Module & code bitness (optional).
279 */
280 g_cBits = ARCH_BITS;
281 if (!strcmp(argv[1], "--32"))
282 {
283 g_cBits = 32;
284 argc--;
285 argv++;
286 }
287 else if (!strcmp(argv[1], "--64"))
288 {
289 g_cBits = 64;
290 argc--;
291 argv++;
292 }
293
294 /*
295 * Load the module.
296 */
297 g_uLoadAddr = (RTUINTPTR)RTStrToUInt64(argv[1]);
298 int rc = RTLdrOpen(argv[2], 0, RTLDRARCH_WHATEVER, &g_hLdrMod);
299 if (RT_FAILURE(rc))
300 {
301 RTPrintf("tstLdr-3: Failed to open '%s': %Rra\n", argv[2], rc);
302 return 1;
303 }
304
305 g_pvBits = RTMemAlloc(RTLdrSize(g_hLdrMod));
306 rc = RTLdrGetBits(g_hLdrMod, g_pvBits, g_uLoadAddr, testGetImport, &g_uLoadAddr);
307 if (RT_SUCCESS(rc))
308 {
309 if ( argc == 4
310 && argv[3][0] == '*')
311 {
312 /*
313 * Wildcard address mode.
314 */
315 uint64_t uWild = RTStrToUInt64(&argv[3][1]);
316 uint64_t uIncrements = strchr(argv[3], '/') ? RTStrToUInt64(strchr(argv[3], '/') + 1) : 0x1000;
317 if (!uIncrements)
318 uIncrements = 0x1000;
319 uint64_t uMax = RTLdrSize(g_hLdrMod) + g_uLoadAddr;
320 for (uint64_t uCur = g_uLoadAddr + uWild; uCur < uMax; uCur += uIncrements)
321 testDisasNear(uCur);
322 }
323 else if (argc > 3)
324 {
325 /*
326 * User specified addresses within the module.
327 */
328 for (int i = 3; i < argc; i++)
329 {
330 rc = testDisasNear(RTStrToUInt64(argv[i]));
331 if (RT_FAILURE(rc))
332 rcRet++;
333 }
334 }
335 else
336 {
337 /*
338 * Enumerate symbols.
339 */
340 rc = RTLdrEnumSymbols(g_hLdrMod, RTLDR_ENUM_SYMBOL_FLAGS_ALL, g_pvBits, g_uLoadAddr, testEnumSymbol1, NULL);
341 if (RT_FAILURE(rc))
342 {
343 RTPrintf("tstLdr-3: Failed to enumerate symbols: %Rra\n", rc);
344 rcRet++;
345 }
346 }
347 }
348 else
349 {
350 RTPrintf("tstLdr-3: Failed to get bits for '%s' at %RTptr: %Rra\n", argv[2], g_uLoadAddr, rc);
351 rcRet++;
352 }
353 RTMemFree(g_pvBits);
354 RTLdrClose(g_hLdrMod);
355
356 /*
357 * Test result summary.
358 */
359 if (!rcRet)
360 RTPrintf("tstLdr-3: SUCCESS\n");
361 else
362 RTPrintf("tstLdr-3: FAILURE - %d errors\n", rcRet);
363 return !!rcRet;
364}
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