VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstLdr-4.cpp@ 100762

Last change on this file since 100762 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 14.3 KB
Line 
1/* $Id: tstLdr-4.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Testcase for RTLdrOpen using ldrLdrObjR0.r0.
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/log.h>
44#include <iprt/stream.h>
45#include <iprt/assert.h>
46#include <iprt/param.h>
47#include <iprt/path.h>
48#include <iprt/err.h>
49#include <iprt/string.h>
50#include <iprt/test.h>
51
52#include <VBox/sup.h>
53
54
55/*********************************************************************************************************************************
56* Global Variables *
57*********************************************************************************************************************************/
58static RTTEST g_hTest;
59static SUPGLOBALINFOPAGE g_MyGip = { SUPGLOBALINFOPAGE_MAGIC, SUPGLOBALINFOPAGE_VERSION, SUPGIPMODE_INVARIANT_TSC, 42 };
60static PSUPGLOBALINFOPAGE g_pMyGip = &g_MyGip;
61
62extern "C" DECLEXPORT(int) DisasmTest1(void);
63
64
65static DECLCALLBACK(int) testEnumSegment(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
66{
67 uint32_t *piSeg = (uint32_t *)pvUser;
68 RTPrintf(" Seg#%02u: %RTptr LB %RTptr %s\n"
69 " link=%RTptr LB %RTptr align=%RTptr fProt=%#x offFile=%RTfoff\n"
70 , *piSeg, pSeg->RVA, pSeg->cbMapped, pSeg->pszName,
71 pSeg->LinkAddress, pSeg->cb, pSeg->Alignment, pSeg->fProt, pSeg->offFile);
72
73 if (pSeg->RVA != NIL_RTLDRADDR)
74 {
75 RTTESTI_CHECK(pSeg->cbMapped != NIL_RTLDRADDR);
76 RTTESTI_CHECK(pSeg->cbMapped >= pSeg->cb);
77 }
78 else
79 {
80 RTTESTI_CHECK(pSeg->cbMapped == NIL_RTLDRADDR);
81 }
82
83 /*
84 * Do some address conversion tests:
85 */
86 if (pSeg->cbMapped != NIL_RTLDRADDR)
87 {
88 /* RTLdrRvaToSegOffset: */
89 uint32_t iSegConv = ~(uint32_t)42;
90 RTLDRADDR offSegConv = ~(RTLDRADDR)22;
91 int rc = RTLdrRvaToSegOffset(hLdrMod, pSeg->RVA, &iSegConv, &offSegConv);
92 if (RT_FAILURE(rc))
93 RTTestIFailed("RTLdrRvaToSegOffset failed on Seg #%u / RVA %#RTptr: %Rrc", *piSeg, pSeg->RVA, rc);
94 else if (iSegConv != *piSeg || offSegConv != 0)
95 RTTestIFailed("RTLdrRvaToSegOffset on Seg #%u / RVA %#RTptr returned: iSegConv=%#x offSegConv=%RTptr, expected %#x and 0",
96 *piSeg, pSeg->RVA, iSegConv, offSegConv, *piSeg);
97
98 /* RTLdrSegOffsetToRva: */
99 RTLDRADDR uRvaConv = ~(RTLDRADDR)22;
100 rc = RTLdrSegOffsetToRva(hLdrMod, *piSeg, 0, &uRvaConv);
101 if (RT_FAILURE(rc))
102 RTTestIFailed("RTLdrSegOffsetToRva failed on Seg #%u / off 0: %Rrc", *piSeg, rc);
103 else if (uRvaConv != pSeg->RVA)
104 RTTestIFailed("RTLdrSegOffsetToRva on Seg #%u / off 0 returned: %RTptr, expected %RTptr", *piSeg, uRvaConv, pSeg->RVA);
105
106 /* RTLdrLinkAddressToRva: */
107 uRvaConv = ~(RTLDRADDR)22;
108 rc = RTLdrLinkAddressToRva(hLdrMod, pSeg->LinkAddress, &uRvaConv);
109 if (RT_FAILURE(rc))
110 RTTestIFailed("RTLdrLinkAddressToRva failed on Seg #%u / %RTptr: %Rrc", *piSeg, pSeg->LinkAddress, rc);
111 else if (uRvaConv != pSeg->RVA)
112 RTTestIFailed("RTLdrLinkAddressToRva on Seg #%u / %RTptr returned: %RTptr, expected %RTptr",
113 *piSeg, pSeg->LinkAddress, uRvaConv, pSeg->RVA);
114
115 /* RTLdrLinkAddressToSegOffset: */
116 iSegConv = ~(uint32_t)42;
117 offSegConv = ~(RTLDRADDR)22;
118 rc = RTLdrLinkAddressToSegOffset(hLdrMod, pSeg->LinkAddress, &iSegConv, &offSegConv);
119 if (RT_FAILURE(rc))
120 RTTestIFailed("RTLdrLinkAddressToSegOffset failed on Seg #%u / %#RTptr: %Rrc", *piSeg, pSeg->LinkAddress, rc);
121 else if (iSegConv != *piSeg || offSegConv != 0)
122 RTTestIFailed("RTLdrLinkAddressToSegOffset on Seg #%u / %#RTptr returned: iSegConv=%#x offSegConv=%RTptr, expected %#x and 0",
123 *piSeg, pSeg->LinkAddress, iSegConv, offSegConv, *piSeg);
124 }
125
126 *piSeg += 1;
127 RT_NOREF(hLdrMod);
128 return VINF_SUCCESS;
129}
130
131
132/**
133 * Resolve an external symbol during RTLdrGetBits().
134 *
135 * @returns iprt status code.
136 * @param hLdrMod The loader module handle.
137 * @param pszModule Module name.
138 * @param pszSymbol Symbol name, NULL if uSymbol should be used.
139 * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
140 * @param pValue Where to store the symbol value (address).
141 * @param pvUser User argument.
142 */
143static DECLCALLBACK(int) testGetImport(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
144{
145 RT_NOREF4(hLdrMod, pszModule, uSymbol, pvUser);
146 if ( !strcmp(pszSymbol, "RTAssertMsg1Weak") || !strcmp(pszSymbol, "_RTAssertMsg1Weak"))
147 *pValue = (uintptr_t)RTAssertMsg1Weak;
148 else if (!strcmp(pszSymbol, "RTAssertMsg2Weak") || !strcmp(pszSymbol, "_RTAssertMsg2Weak"))
149 *pValue = (uintptr_t)RTAssertMsg1Weak;
150 else if (!strcmp(pszSymbol, "RTAssertMsg1") || !strcmp(pszSymbol, "_RTAssertMsg1"))
151 *pValue = (uintptr_t)RTAssertMsg1;
152 else if (!strcmp(pszSymbol, "RTAssertMsg2") || !strcmp(pszSymbol, "_RTAssertMsg2"))
153 *pValue = (uintptr_t)RTAssertMsg2;
154 else if (!strcmp(pszSymbol, "RTAssertMsg2V") || !strcmp(pszSymbol, "_RTAssertMsg2V"))
155 *pValue = (uintptr_t)RTAssertMsg2V;
156 else if (!strcmp(pszSymbol, "RTAssertMayPanic") || !strcmp(pszSymbol, "_RTAssertMayPanic"))
157 *pValue = (uintptr_t)RTAssertMayPanic;
158 else if (!strcmp(pszSymbol, "RTLogDefaultInstanceEx") || !strcmp(pszSymbol, "RTLogDefaultInstanceEx"))
159 *pValue = (uintptr_t)RTLogDefaultInstanceEx;
160 else if (!strcmp(pszSymbol, "RTLogLoggerExV") || !strcmp(pszSymbol, "_RTLogLoggerExV"))
161 *pValue = (uintptr_t)RTLogLoggerExV;
162 else if (!strcmp(pszSymbol, "RTLogPrintfV") || !strcmp(pszSymbol, "_RTLogPrintfV"))
163 *pValue = (uintptr_t)RTLogPrintfV;
164 else if (!strcmp(pszSymbol, "RTR0AssertPanicSystem")|| !strcmp(pszSymbol, "_RTR0AssertPanicSystem"))
165 *pValue = (uintptr_t)0;
166 else if (!strcmp(pszSymbol, "MyPrintf") || !strcmp(pszSymbol, "_MyPrintf"))
167 *pValue = (uintptr_t)RTPrintf;
168 else if (!strcmp(pszSymbol, "SUPR0Printf") || !strcmp(pszSymbol, "_SUPR0Printf"))
169 *pValue = (uintptr_t)RTPrintf;
170 else if (!strcmp(pszSymbol, "SUPR0PrintfV") || !strcmp(pszSymbol, "_SUPR0PrintfV"))
171 *pValue = (uintptr_t)RTPrintfV;
172 else if (!strcmp(pszSymbol, "SomeImportFunction") || !strcmp(pszSymbol, "_SomeImportFunction"))
173 *pValue = (uintptr_t)0;
174 else if (!strcmp(pszSymbol, "g_pSUPGlobalInfoPage") || !strcmp(pszSymbol, "_g_pSUPGlobalInfoPage"))
175 *pValue = (uintptr_t)&g_pMyGip;
176 else if (!strcmp(pszSymbol, "g_SUPGlobalInfoPage") || !strcmp(pszSymbol, "_g_SUPGlobalInfoPage"))
177 *pValue = (uintptr_t)&g_MyGip;
178 else
179 {
180 RTPrintf("tstLdr-4: Unexpected import '%s'!\n", pszSymbol);
181 return VERR_SYMBOL_NOT_FOUND;
182 }
183 return VINF_SUCCESS;
184}
185
186
187/**
188 * One test iteration with one file.
189 *
190 * The test is very simple, we load the file three times
191 * into two different regions. The first two into each of the
192 * regions the for compare usage. The third is loaded into one
193 * and then relocated between the two and other locations a few times.
194 *
195 * @param pszFilename The file to load the mess with.
196 */
197static void testLdrOne(const char *pszFilename)
198{
199 RTTestSub(g_hTest, RTPathFilename(pszFilename));
200
201 size_t cbImage = 0;
202 struct Load
203 {
204 RTLDRMOD hLdrMod;
205 void *pvBits;
206 size_t cbBits;
207 const char *pszName;
208 } aLoads[6] =
209 {
210 { NULL, NULL, 0, "foo" },
211 { NULL, NULL, 0, "bar" },
212 { NULL, NULL, 0, "foobar" },
213 };
214 unsigned i;
215 int rc;
216
217 /*
218 * Load them.
219 */
220 for (i = 0; i < RT_ELEMENTS(aLoads); i++)
221 {
222 rc = RTLdrOpen(pszFilename, 0, RTLDRARCH_WHATEVER, &aLoads[i].hLdrMod);
223 if (RT_FAILURE(rc))
224 {
225 RTTestIFailed("tstLdr-4: Failed to open '%s'/%d, rc=%Rrc. aborting test.", pszFilename, i, rc);
226 Assert(aLoads[i].hLdrMod == NIL_RTLDRMOD);
227 break;
228 }
229
230 /* size it */
231 size_t cb = RTLdrSize(aLoads[i].hLdrMod);
232 if (cbImage && cb != cbImage)
233 {
234 RTTestIFailed("tstLdr-4: Size mismatch '%s'/%d. aborting test.", pszFilename, i);
235 break;
236 }
237 aLoads[i].cbBits = cbImage = cb;
238
239 /* Allocate bits. */
240 aLoads[i].pvBits = RTMemPageAlloc(cb);
241 if (!aLoads[i].pvBits)
242 {
243 RTTestIFailed("Out of memory '%s'/%d cbImage=%d. aborting test.", pszFilename, i, cbImage);
244 break;
245 }
246 rc = RTMemProtect(aLoads[i].pvBits, cb, RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC);
247 if (RT_FAILURE(rc))
248 {
249 RTTestIFailed("RTMemProtect/RWX '%s'/%d cbImage=%d, %Rrc. aborting test.", pszFilename, i, cbImage, rc);
250 break;
251 }
252
253 /* Get the bits. */
254 rc = RTLdrGetBits(aLoads[i].hLdrMod, aLoads[i].pvBits, (uintptr_t)aLoads[i].pvBits, testGetImport, NULL);
255 if (RT_FAILURE(rc))
256 {
257 RTTestIFailed("Failed to get bits for '%s'/%d, rc=%Rrc. aborting test", pszFilename, i, rc);
258 break;
259 }
260 }
261
262 /*
263 * Execute the code.
264 */
265 if (!RTTestSubErrorCount(g_hTest))
266 {
267 for (i = 0; i < RT_ELEMENTS(aLoads); i += 1)
268 {
269 /* VERR_ELF_EXE_NOT_SUPPORTED in the previous loop? */
270 if (!aLoads[i].hLdrMod)
271 continue;
272 /* get the pointer. */
273 RTUINTPTR Value;
274 rc = RTLdrGetSymbolEx(aLoads[i].hLdrMod, aLoads[i].pvBits, (uintptr_t)aLoads[i].pvBits,
275 UINT32_MAX, "DisasmTest1", &Value);
276 if (rc == VERR_SYMBOL_NOT_FOUND)
277 rc = RTLdrGetSymbolEx(aLoads[i].hLdrMod, aLoads[i].pvBits, (uintptr_t)aLoads[i].pvBits,
278 UINT32_MAX, "_DisasmTest1", &Value);
279 if (RT_FAILURE(rc))
280 {
281 RTTestIFailed("Failed to get symbol \"DisasmTest1\" from load #%d: %Rrc", i, rc);
282 break;
283 }
284 typedef DECLCALLBACKPTR(int, PFNDISASMTEST1,(void));
285 PFNDISASMTEST1 pfnDisasmTest1 = (PFNDISASMTEST1)(uintptr_t)Value;
286 RTPrintf("tstLdr-4: pfnDisasmTest1=%p / add-symbol-file %s %#p\n", pfnDisasmTest1, pszFilename, aLoads[i].pvBits);
287 uint32_t iSeg = 0;
288 RTLdrEnumSegments(aLoads[i].hLdrMod, testEnumSegment, &iSeg);
289
290 /* call the test function. */
291 rc = pfnDisasmTest1();
292 if (rc)
293 RTTestIFailed("load #%d Test1 -> %#x", i, rc);
294
295 /* While we're here, check a couple of RTLdrQueryProp calls too */
296 void *pvBits = aLoads[i].pvBits;
297 for (unsigned iBits = 0; iBits < 2; iBits++, pvBits = NULL)
298 {
299 union
300 {
301 char szName[127];
302 } uBuf;
303 rc = RTLdrQueryPropEx(aLoads[i].hLdrMod, RTLDRPROP_INTERNAL_NAME, aLoads[i].pvBits,
304 uBuf.szName, sizeof(uBuf.szName), NULL);
305 if (RT_SUCCESS(rc))
306 RTPrintf("tstLdr-4: internal name #%d: '%s'\n", i, uBuf.szName);
307 else if (rc != VERR_NOT_FOUND && rc != VERR_NOT_SUPPORTED)
308 RTPrintf("tstLdr-4: internal name #%d failed: %Rrc\n", i, rc);
309 }
310 }
311 }
312
313 /*
314 * Clean up.
315 */
316 for (i = 0; i < RT_ELEMENTS(aLoads); i++)
317 {
318 if (aLoads[i].pvBits)
319 {
320 RTMemProtect(aLoads[i].pvBits, aLoads[i].cbBits, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
321 RTMemPageFree(aLoads[i].pvBits, aLoads[i].cbBits);
322 }
323 if (aLoads[i].hLdrMod)
324 {
325 rc = RTLdrClose(aLoads[i].hLdrMod);
326 if (RT_FAILURE(rc))
327 RTTestIFailed("Failed to close '%s' i=%d, rc=%Rrc.", pszFilename, i, rc);
328 }
329 }
330
331}
332
333
334
335int main()
336{
337 RTEXITCODE rcExit = RTTestInitAndCreate("tstLdr-4", &g_hTest);
338 if (rcExit != RTEXITCODE_SUCCESS)
339 return rcExit;
340
341 /*
342 * Sanity check.
343 */
344 int rc = DisasmTest1();
345 if (rc == 0)
346 {
347 /*
348 * Execute the test.
349 */
350 char szPath[RTPATH_MAX];
351 rc = RTPathExecDir(szPath, sizeof(szPath) - sizeof("/tstLdrObjR0.r0"));
352 if (RT_SUCCESS(rc))
353 {
354 strcat(szPath, "/tstLdrObjR0.r0");
355
356 testLdrOne(szPath);
357 }
358 else
359 RTTestIFailed("RTPathExecDir -> %Rrc", rc);
360 }
361 else
362 RTTestIFailed("FATAL ERROR - DisasmTest1 is buggy: rc=%#x", rc);
363
364 return RTTestSummaryAndDestroy(g_hTest);
365}
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