VirtualBox

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

Last change on this file since 53401 was 48935, checked in by vboxsync, 11 years ago

Runtime: Whitespace and svn:keyword cleanups by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 11.4 KB
Line 
1/* $Id: tstLdr-3.cpp 48935 2013-10-07 21:19:37Z vboxsync $ */
2/** @file
3 * IPRT - Testcase for parts of RTLdr*, manual inspection.
4 */
5
6/*
7 * Copyright (C) 2006-2012 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 DISFormatYasmEx(&Cpu, szOutput, sizeof(szOutput),
178 DIS_FMT_FLAGS_RELATIVE_BRANCH | DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_ADDR_LEFT | DIS_FMT_FLAGS_BYTES_SPACED,
179 MyGetSymbol, NULL);
180
181 RTPrintf("%s\n", szOutput);
182 if (pvCodeBlock + i + off == uSearchAddr)
183 RTPrintf("^^^^^^^^\n");
184
185 /* next */
186 i += cbInstr;
187 }
188 return true;
189}
190
191
192
193/**
194 * Resolve an external symbol during RTLdrGetBits().
195 *
196 * @returns iprt status code.
197 * @param hLdrMod The loader module handle.
198 * @param pszModule Module name.
199 * @param pszSymbol Symbol name, NULL if uSymbol should be used.
200 * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
201 * @param pValue Where to store the symbol value (address).
202 * @param pvUser User argument.
203 */
204static DECLCALLBACK(int) testGetImport(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
205{
206#if 1
207 RTUINTPTR BaseAddr = *(PCRTUINTPTR)pvUser;
208 *pValue = BaseAddr + UINT32_C(0x604020f0);
209#else
210 *pValue = UINT64_C(0xffffff7f820df000);
211#endif
212 if (g_cBits == 32)
213 *pValue &= UINT32_MAX;
214 return VINF_SUCCESS;
215}
216
217
218/**
219 * Enumeration callback function used by RTLdrEnumSymbols().
220 *
221 * @returns iprt status code. Failure will stop the enumeration.
222 * @param hLdrMod The loader module handle.
223 * @param pszSymbol Symbol name. NULL if ordinal only.
224 * @param uSymbol Symbol ordinal, ~0 if not used.
225 * @param Value Symbol value.
226 * @param pvUser The user argument specified to RTLdrEnumSymbols().
227 */
228static DECLCALLBACK(int) testEnumSymbol1(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
229{
230 RTPrintf(" %RTptr %s (%d)\n", Value, pszSymbol, uSymbol);
231 return VINF_SUCCESS;
232}
233
234
235static int testDisasNear(uint64_t uAddr)
236{
237 TESTNEARSYM NearSym;
238 int rc = FindNearSymbol(uAddr, &NearSym);
239 if (RT_FAILURE(rc))
240 return rc;
241
242 RTPrintf("tstLdr-3: Addr=%RTptr\n"
243 "%RTptr %s (%d) - %RTptr %s (%d)\n",
244 NearSym.Addr,
245 NearSym.aSyms[0].Value, NearSym.aSyms[0].szName, NearSym.aSyms[0].uSymbol,
246 NearSym.aSyms[1].Value, NearSym.aSyms[1].szName, NearSym.aSyms[1].uSymbol);
247 if (NearSym.Addr - NearSym.aSyms[0].Value < 0x10000)
248 {
249 DISCPUMODE enmDisCpuMode = g_cBits == 32 ? DISCPUMODE_32BIT : DISCPUMODE_64BIT;
250 uint8_t *pbCode = (uint8_t *)g_pvBits + (NearSym.aSyms[0].Value - g_uLoadAddr);
251 MyDisBlock(enmDisCpuMode, (uintptr_t)pbCode,
252 RT_MAX(NearSym.aSyms[1].Value - NearSym.aSyms[0].Value, 0x20000),
253 NearSym.aSyms[0].Value - (RTUINTPTR)pbCode,
254 NearSym.aSyms[0].Value,
255 NearSym.Addr);
256 }
257
258 return VINF_SUCCESS;
259}
260
261int main(int argc, char **argv)
262{
263 RTR3InitExe(argc, &argv, 0);
264
265 int rcRet = 0;
266 if (argc <= 2)
267 {
268 RTPrintf("usage: %s <load-addr> <module> [addr1 []]\n", argv[0]);
269 return 1;
270 }
271
272 /*
273 * Module & code bitness (optional).
274 */
275 g_cBits = ARCH_BITS;
276 if (!strcmp(argv[1], "--32"))
277 {
278 g_cBits = 32;
279 argc--;
280 argv++;
281 }
282 else if (!strcmp(argv[1], "--64"))
283 {
284 g_cBits = 64;
285 argc--;
286 argv++;
287 }
288
289 /*
290 * Load the module.
291 */
292 g_uLoadAddr = (RTUINTPTR)RTStrToUInt64(argv[1]);
293 int rc = RTLdrOpen(argv[2], 0, RTLDRARCH_WHATEVER, &g_hLdrMod);
294 if (RT_FAILURE(rc))
295 {
296 RTPrintf("tstLdr-3: Failed to open '%s': %Rra\n", argv[2], rc);
297 return 1;
298 }
299
300 g_pvBits = RTMemAlloc(RTLdrSize(g_hLdrMod));
301 rc = RTLdrGetBits(g_hLdrMod, g_pvBits, g_uLoadAddr, testGetImport, &g_uLoadAddr);
302 if (RT_SUCCESS(rc))
303 {
304 if ( argc == 4
305 && argv[3][0] == '*')
306 {
307 /*
308 * Wildcard address mode.
309 */
310 uint64_t uWild = RTStrToUInt64(&argv[3][1]);
311 uint64_t uIncrements = strchr(argv[3], '/') ? RTStrToUInt64(strchr(argv[3], '/') + 1) : 0x1000;
312 if (!uIncrements)
313 uIncrements = 0x1000;
314 uint64_t uMax = RTLdrSize(g_hLdrMod) + g_uLoadAddr;
315 for (uint64_t uCur = g_uLoadAddr + uWild; uCur < uMax; uCur += uIncrements)
316 testDisasNear(uCur);
317 }
318 else if (argc > 3)
319 {
320 /*
321 * User specified addresses within the module.
322 */
323 for (int i = 3; i < argc; i++)
324 {
325 rc = testDisasNear(RTStrToUInt64(argv[i]));
326 if (RT_FAILURE(rc))
327 rcRet++;
328 }
329 }
330 else
331 {
332 /*
333 * Enumerate symbols.
334 */
335 rc = RTLdrEnumSymbols(g_hLdrMod, RTLDR_ENUM_SYMBOL_FLAGS_ALL, g_pvBits, g_uLoadAddr, testEnumSymbol1, NULL);
336 if (RT_FAILURE(rc))
337 {
338 RTPrintf("tstLdr-3: Failed to enumerate symbols: %Rra\n", rc);
339 rcRet++;
340 }
341 }
342 }
343 else
344 {
345 RTPrintf("tstLdr-3: Failed to get bits for '%s' at %RTptr: %Rra\n", argv[2], g_uLoadAddr, rc);
346 rcRet++;
347 }
348 RTMemFree(g_pvBits);
349 RTLdrClose(g_hLdrMod);
350
351 /*
352 * Test result summary.
353 */
354 if (!rcRet)
355 RTPrintf("tstLdr-3: SUCCESS\n");
356 else
357 RTPrintf("tstLdr-3: FAILURE - %d errors\n", rcRet);
358 return !!rcRet;
359}
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