source: trunk/kLdr/tstkLdrMod.c@ 2860

Last change on this file since 2860 was 2860, checked in by bird, 19 years ago

Working on the mapping stuff (windows is gonna be a headache).

File size: 15.7 KB
RevLine 
[2859]1/* $Id: kLdrRdrFile.c 2857 2006-11-05 04:12:13Z bird $ */
2/** @file
3 *
4 * kLdr - Module interpreter testcase.
5 *
6 * Copyright (c) 2006 knut st. osmundsen <bird-kbuild-src@anduin.net>
7 *
8 *
9 * This file is part of kLdr.
10 *
11 * kLdr is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * kLdr is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kLdr; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <kLdr.h>
32#include <stdarg.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36
37
38/*******************************************************************************
39* Defined Constants And Macros *
40*******************************************************************************/
41/** The default base address used in the tests. */
42#define MY_BASEADDRESS 0x4200000
43
44
45/*******************************************************************************
46* Global Variables *
47*******************************************************************************/
48/** The numbers of errors. */
49static int g_cErrors = 0;
50
51
52
53/**
54 * Report failure.
55 */
56static int Failure(const char *pszFormat, ...)
57{
58 va_list va;
59
60 g_cErrors++;
61
62 printf("tstLdrMod: ");
63 va_start(va, pszFormat);
64 vprintf(pszFormat, va);
65 va_end(va);
66 printf("\n");
67 return 1;
68}
69
70
71/**
72 * Dump symbols and check that we can query each of them recursivly.
73 */
74static int BasicTestsEnumSymCallback(PKLDRMOD pMod, uint32_t iSymbol, const char *pszSymbol,
75 KLDRADDR uValue, uint32_t fKind, void *pvUser)
76{
77 KLDRADDR uValue2;
78 uint32_t fKind2;
79 int rc;
80
81 /* dump */
82 printf("#0x%08x: %016" PRI_KLDRADDR " %#08x", iSymbol, uValue, fKind);
83 if (pszSymbol)
84 printf(" %s", pszSymbol);
85 printf("\n");
86
87 /* query by ordinal */
88 if (iSymbol != NIL_KLDRMOD_SYM_ORDINAL)
89 {
90 rc = kLdrModQuerySymbol(pMod, pvUser, MY_BASEADDRESS, iSymbol, NULL, NULL, NULL,
91 &uValue2, &fKind2);
92 if (rc)
93 return Failure("Couldn't find symbol %#x (%s) by ordinal. rc=%d\n", iSymbol, pszSymbol, rc);
94 if (uValue != uValue2)
95 return Failure("Symbol %#x (%s): Value mismatch %016" PRI_KLDRADDR " != %016" PRI_KLDRADDR " (enum!=query/ord) pvBits=%p\n",
96 iSymbol, pszSymbol, uValue, uValue2, pvUser);
97 if (fKind != fKind2)
98 return Failure("Symbol %#x (%s): Kind mismatch %#x != %#x (enum!=query/ord) pvBits=%p\n",
99 iSymbol, pszSymbol, fKind, fKind2, pvUser);
100 }
101
102 /* query by name. */
103 if (pszSymbol)
104 {
105 rc = kLdrModQuerySymbol(pMod, pvUser, MY_BASEADDRESS, NIL_KLDRMOD_SYM_ORDINAL, pszSymbol, NULL, NULL,
106 &uValue2, &fKind2);
107 if (rc)
108 return Failure("Couldn't find symbol %#x (%s) by name. rc=%d\n", iSymbol, pszSymbol, rc);
109 if (uValue != uValue2)
110 return Failure("Symbol %#x (%s): Value mismatch %016" PRI_KLDRADDR " != %016" PRI_KLDRADDR " (enum!=query/name) pvBits=%p\n",
111 iSymbol, pszSymbol, uValue, uValue2, pvUser);
112 if (fKind != fKind2)
113 return Failure("Symbol %#x (%s): Kind mismatch %#x != %#x (enum!=query/name) pvBits=%p\n",
114 iSymbol, pszSymbol, fKind, fKind2, pvUser);
115 }
116
117 return 0;
118}
119
120
121/**
122 * Dump debugger information and check it for correctness.
123 */
124static int BasicTestEnumDbgInfoCallback(PKLDRMOD pMod, uint32_t iDbgInfo, KLDRDBGINFOTYPE enmType,
125 int16_t iMajorVer, int16_t iMinorVer, off_t offFile, KLDRADDR LinkAddress,
126 KLDRSIZE cb, const char *pszExtFile, void *pvUser)
127{
128 printf("#0x%08x: enmType=%d %d.%d offFile=0x%" PRI_KLDRADDR " LinkAddress=%" PRI_KLDRADDR " cb=%" PRI_KLDRSIZE " pvUser=%p\n",
129 iDbgInfo, enmType, iMajorVer, iMinorVer, (KLDRADDR)offFile, LinkAddress, cb, pvUser);
130 if (pszExtFile)
131 printf(" pszExtFile=%p '%s'\n", pszExtFile, pszExtFile);
132
133 if (enmType >= KLDRDBGINFOTYPE_END || enmType <= KLDRDBGINFOTYPE_INVALID)
134 return Failure("Bad enmType");
135 if (pvUser != NULL)
136 return Failure("pvUser");
137
138 return 0;
139}
140
141
142/**
143 * Performs the basic module loader test on the specified module and image bits.
144 */
145static int BasicTestsSub2(PKLDRMOD pMod, void *pvBits)
146{
147 int32_t cImports;
148 int32_t i;
149 int rc;
150 uint32_t fKind;
151 KLDRADDR Value;
152 KLDRADDR MainEPAddress;
153 KLDRSTACKINFO StackInfo;
154
155 /*
156 * Get the import modules.
157 */
158 cImports = kLdrModNumberOfImports(pMod, pvBits);
159 printf("cImports=%d\n", cImports);
160 if (cImports < 0)
161 return Failure("failed to allocate %d bytes for the image", cImports);
162 for (i = 0; i < cImports; i++)
163 {
164 char szImportModule[260];
165 rc = kLdrModGetImport(pMod, pvBits, i, szImportModule, sizeof(szImportModule));
166 if (rc)
167 return Failure("failed to get import module name, rc=%d. (%.260s)", rc, szImportModule);
168 printf("import #%d: '%s'\n", i, szImportModule);
169 }
170
171 /*
172 * Query stack info.
173 */
174 StackInfo.Address = ~(KLDRADDR)42;
175 StackInfo.LinkAddress = ~(KLDRADDR)42;
176 StackInfo.cbStack = ~(KLDRSIZE)42;
177 StackInfo.cbStackThread = ~(KLDRSIZE)42;
178 rc = kLdrModGetStackInfo(pMod, pvBits, MY_BASEADDRESS, &StackInfo);
179 if (rc)
180 return Failure("kLdrModGetStackInfo failed with rc=%d", rc);
181 printf("Stack: Address=%016" PRI_KLDRADDR " LinkAddress=%016" PRI_KLDRADDR "\n"
182 " cbStack=%016" PRI_KLDRSIZE " cbStackThread=%016" PRI_KLDRSIZE "\n",
183 StackInfo.Address, StackInfo.LinkAddress, StackInfo.cbStack, StackInfo.cbStackThread);
184 if (StackInfo.Address == ~(KLDRADDR)42)
185 return Failure("Bad StackInfo.Address");
186 if (StackInfo.LinkAddress == ~(KLDRADDR)42)
187 return Failure("Bad StackInfo.LinkAddress");
188 if (StackInfo.cbStack == ~(KLDRSIZE)42)
189 return Failure("Bad StackInfo.cbStack");
190 if (StackInfo.cbStackThread == ~(KLDRSIZE)42)
191 return Failure("Bad StackInfo.cbStackThread");
192
193 /*
194 * Query entrypoint.
195 */
196 MainEPAddress = ~(KLDRADDR)42;
197 rc = kLdrModQueryMainEntrypoint(pMod, pvBits, MY_BASEADDRESS, &MainEPAddress);
198 if (rc)
199 return Failure("kLdrModQueryMainEntrypoint failed with rc=%d", rc);
200 printf("Entrypoint: %016" PRI_KLDRADDR "\n", MainEPAddress);
201 if (MainEPAddress == ~(KLDRADDR)42)
202 return Failure("MainEPAddress wasn't set.");
203
204 /*
205 * Debugger information.
206 */
207 rc = kLdrModHasDbgInfo(pMod, pvBits);
208 if (!rc)
209 printf("Has Debugger Information\n");
210 else if (rc == KLDR_ERR_NO_DEBUG_INFO)
211 printf("NO Debugger Information\n");
212 else
213 return Failure("kLdrModHasDbgInfo failed with rc=%d", rc);
214 rc = kLdrModEnumDbgInfo(pMod, pvBits, BasicTestEnumDbgInfoCallback, NULL);
215 if (rc)
216 return Failure("kLdrModEnumDbgInfo failed with rc=%d", rc);
217
218
219 /*
220 * Negative symbol query tests.
221 */
222 fKind = 0xdeadf00d;
223 Value = 0x0badc0de;
224 rc = kLdrModQuerySymbol(pMod, pvBits, MY_BASEADDRESS, NIL_KLDRMOD_SYM_ORDINAL - 20, NULL, NULL, NULL,
225 &Value, &fKind);
226 if (rc)
227 {
228 if (fKind != 0)
229 return Failure("fKind wasn't cleared on failure.");
230 if (Value != 0)
231 return Failure("Value wasn't cleared on failure.");
232 }
233
234 fKind = 0xdeadf00d;
235 Value = 0x0badc0de;
236 rc = kLdrModQuerySymbol(pMod, pvBits, MY_BASEADDRESS, NIL_KLDRMOD_SYM_ORDINAL, NULL, NULL, NULL,
237 &Value, &fKind);
238 if (!rc)
239 return Failure("NIL ordinal succeeded!");
240 if (fKind != 0)
241 return Failure("fKind wasn't cleared on failure.");
242 if (Value != 0)
243 return Failure("Value wasn't cleared on failure.");
244
245 /*
246 * Enumerate and query all symbols.
247 */
248 printf("\n"
249 "Symbols:\n");
250 rc = kLdrModEnumSymbols(pMod, pvBits, MY_BASEADDRESS, 0, BasicTestsEnumSymCallback, pvBits);
251 if (rc)
252 return Failure("kLdrModEnumSymbols failed with rc=%d", rc);
253
254
255/*int kLdrModCanExecuteOn(PKLDRMOD pMod, const void *pvBits, KLDRARCH enmArch, KLDRCPU enmCpu);
256*/
257
258 return 0;
259}
260
261
262/** Dummy import resolver callback. */
263static int BasicTestsGetImport(PKLDRMOD pMod, uint32_t iImport, uint32_t iSymbol, const char *pszSymbol,
264 PKLDRADDR puValue, uint32_t *pfKind, void *pvUser)
265{
266 *puValue = 0xdeadface;
267 *pfKind = KLDRSYMKIND_NO_BIT | KLDRSYMKIND_NO_TYPE;
268 return 0;
269}
270
271
272/**
273 * Performs the basic module loader test on the specified module
274 */
275static int BasicTestsSub(PKLDRMOD pMod)
276{
277 int rc;
278 uint32_t i;
279 void *pvBits;
280 size_t cbImage;
281
282 /*
283 * Check/dump the module structure.
284 */
285 printf("pMod=%p u32Magic=%#x cSegments=%d\n", pMod, pMod->u32Magic, pMod->cSegments);
286 printf("enmType=%d enmFmt=%d enmArch=%d enmCpu=%d enmEndian=%d\n",
287 pMod->enmType, pMod->enmFmt, pMod->enmArch, pMod->enmCpu, pMod->enmEndian);
288 printf("Filename: %s (%d bytes)\n", pMod->pszFilename, pMod->cchFilename);
289 printf(" Name: %s (%d bytes)\n", pMod->pszName, pMod->cchName);
290 printf("\n");
291
292 if (pMod->u32Magic != KLDRMOD_MAGIC)
293 return Failure("Bad u32Magic");
294 if (strlen(pMod->pszFilename) != pMod->cchFilename)
295 return Failure("Bad cchFilename");
296 if (strlen(pMod->pszName) != pMod->cchName)
297 return Failure("Bad cchName");
298 if (pMod->enmFmt >= KLDRFMT_END || pMod->enmFmt <= KLDRFMT_INVALID)
299 return Failure("Bad enmFmt");
300 if (pMod->enmType >= KLDRTYPE_END || pMod->enmType <= KLDRTYPE_INVALID)
301 return Failure("Bad enmType: %d", pMod->enmType);
302 if (pMod->enmArch >= KLDRARCH_END || pMod->enmArch <= KLDRARCH_INVALID)
303 return Failure("Bad enmArch");
304 if (pMod->enmCpu >= KLDRCPU_END || pMod->enmCpu <= KLDRCPU_INVALID)
305 return Failure("Bad enmCpu");
306 if (pMod->enmEndian >= KLDRENDIAN_END || pMod->enmEndian <= KLDRENDIAN_INVALID)
307 return Failure("Bad enmEndian");
308
309 for (i = 0; i < pMod->cSegments; i++)
310 {
311 printf("seg #%d: pvUser=%p enmProt=%d Name: '%.*s' (%d bytes)\n",
312 i, pMod->aSegments[i].pvUser, pMod->aSegments[i].enmProt,
313 pMod->aSegments[i].cchName, pMod->aSegments[i].pchName, pMod->aSegments[i].cchName);
314 printf("LinkAddress: %016" PRI_KLDRADDR " cb: %016" PRI_KLDRSIZE " Alignment=%08" PRI_KLDRADDR " \n",
315 pMod->aSegments[i].LinkAddress, pMod->aSegments[i].cb, pMod->aSegments[i].Alignment);
316 printf(" RVA: %016" PRI_KLDRADDR " cbMapped: %016" PRI_KLDRSIZE " MapAddress=%p\n",
317 pMod->aSegments[i].RVA, (KLDRSIZE)pMod->aSegments[i].cbMapped, pMod->aSegments[i].MapAddress);
318 printf(" offFile: %016" PRI_KLDRADDR " cbFile: %016" PRI_KLDRSIZE "\n",
319 (KLDRADDR)pMod->aSegments[i].offFile, (KLDRSIZE)pMod->aSegments[i].cbFile);
320 printf("\n");
321
322 if (pMod->aSegments[i].pvUser != NULL)
323 return Failure("Bad pvUser");
324 if (pMod->aSegments[i].enmProt >= KLDRPROT_END || pMod->aSegments[i].enmProt <= KLDRPROT_INVALID)
325 return Failure("Bad enmProt");
326 if (pMod->aSegments[i].MapAddress != 0)
327 return Failure("Bad MapAddress");
328 if (pMod->aSegments[i].cbMapped < pMod->aSegments[i].cb)
329 return Failure("Bad cbMapped (1)");
330 if (pMod->aSegments[i].cbMapped && !pMod->aSegments[i].Alignment)
331 return Failure("Bad cbMapped (2)");
332 if (pMod->aSegments[i].cbMapped > kLdrModSize(pMod))
333 return Failure("Bad cbMapped (3)");
334 if ( pMod->aSegments[i].Alignment
335 && (pMod->aSegments[i].RVA & (pMod->aSegments[i].Alignment - 1)))
336 return Failure("Bad RVA (1)");
337 if (pMod->aSegments[i].RVA != NIL_KLDRADDR && !pMod->aSegments[i].Alignment)
338 return Failure("Bad RVA (2)");
339 if ( pMod->aSegments[i].RVA != NIL_KLDRADDR
340 && pMod->aSegments[i].RVA >= kLdrModSize(pMod))
341 return Failure("Bad RVA (3)");
342 if ( pMod->aSegments[i].RVA != NIL_KLDRADDR
343 && pMod->aSegments[i].RVA + pMod->aSegments[i].cbMapped > kLdrModSize(pMod))
344 return Failure("Bad RVA/cbMapped (4)");
345 if (pMod->aSegments[i].LinkAddress != NIL_KLDRADDR && !pMod->aSegments[i].Alignment)
346 return Failure("Bad LinkAddress");
347 if ( pMod->aSegments[i].LinkAddress != NIL_KLDRADDR
348 && (pMod->aSegments[i].LinkAddress) & (pMod->aSegments[i].Alignment - 1))
349 return Failure("Bad LinkAddress alignment");
350 if (pMod->aSegments[i].offFile != -1 && pMod->aSegments[i].cbFile == -1)
351 return Failure("Bad offFile");
352 if (pMod->aSegments[i].offFile == -1 && pMod->aSegments[i].cbFile != -1)
353 return Failure("Bad cbFile");
354 }
355
356 /*
357 * Get image the size and query the image bits.
358 */
359 cbImage = (size_t)kLdrModSize(pMod);
360 if (cbImage != kLdrModSize(pMod))
361 return Failure("aborting test because the image is too huge!\n");
362 pvBits = malloc((size_t)cbImage);
363 if (!pvBits)
364 return Failure("failed to allocate %d bytes for the image\n", cbImage);
365
366 rc = kLdrModGetBits(pMod, pvBits, (uintptr_t)pvBits, BasicTestsGetImport, NULL);
367 if (rc)
368 return Failure("failed to allocate %d bytes for the image\n", cbImage);
369
370 /*
371 * Another cleanup nesting.
372 */
373 rc = BasicTestsSub2(pMod, pvBits);
374 free(pvBits);
375 return rc;
376}
377
378
379/**
[2860]380 * Tests the mapping related api.
381 */
382static int BasicTestsSubMap(PKLDRMOD pMod)
383{
384 int rc;
385
386 rc = kLdrModMap(pMod);
387 if (rc)
388 return Failure("kLdrModMap failed, rc=%d\n", rc);
389
390 return 0;
391}
392
393
394/**
[2859]395 * Performs basic module loader tests on the specified file.
396 */
397static int BasicTests(const char *pszFilename)
398{
399 PKLDRMOD pMod;
400 int rc, rc2;
401
402 printf("tstLdrMod: Testing '%s'\n", pszFilename);
403 rc = kLdrModOpen(pszFilename, &pMod);
404 if (!rc)
405 {
406 rc = BasicTestsSub(pMod);
[2860]407 if (!rc)
408 rc = BasicTestsSubMap(pMod);
[2859]409 rc2 = kLdrModClose(pMod);
410 if (rc2)
411 Failure("failed to close '%s', rc=%d\n", pszFilename, rc);
412 if (rc2 && !rc)
413 rc = rc2;
414 }
415 else
416 Failure("Failed to open '%s', rc=%d\n", pszFilename, rc);
417 return rc ? 1 : 0;
418}
419
420
421int main(int argc, char **argv)
422{
423 BasicTests(argv[argc-1]);
424
425 if (!g_cErrors)
426 printf("tstLdrMod: SUCCESS\n");
427 else
428 printf("tstLdrMod: FAILURE - %d errors\n", g_cErrors);
429 return !!g_cErrors;
430}
431
Note: See TracBrowser for help on using the repository browser.