| [2878] | 1 | /* $Id: tstkLdrMod.c 2974 2007-02-14 10:12:44Z bird $ */ | 
|---|
| [2859] | 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. */ | 
|---|
| [2861] | 42 | #define MY_BASEADDRESS      0x2400000 | 
|---|
| [2859] | 43 |  | 
|---|
|  | 44 |  | 
|---|
|  | 45 | /******************************************************************************* | 
|---|
|  | 46 | *   Global Variables                                                           * | 
|---|
|  | 47 | *******************************************************************************/ | 
|---|
|  | 48 | /** The numbers of errors. */ | 
|---|
|  | 49 | static int g_cErrors = 0; | 
|---|
|  | 50 |  | 
|---|
|  | 51 |  | 
|---|
|  | 52 |  | 
|---|
|  | 53 | /** | 
|---|
|  | 54 | * Report failure. | 
|---|
|  | 55 | */ | 
|---|
|  | 56 | static 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 |  | 
|---|
| [2861] | 71 | /** Dummy import resolver callback. */ | 
|---|
| [2899] | 72 | static int BasicTestsGetImport(PKLDRMOD pMod, uint32_t iImport, uint32_t iSymbol, const char *pchSymbol, size_t cchSymbol, | 
|---|
|  | 73 | const char *pszVersion, PKLDRADDR puValue, uint32_t *pfKind, void *pvUser) | 
|---|
| [2861] | 74 | { | 
|---|
|  | 75 | *puValue = 0xdeadface; | 
|---|
|  | 76 | *pfKind = KLDRSYMKIND_NO_BIT | KLDRSYMKIND_NO_TYPE; | 
|---|
|  | 77 | return 0; | 
|---|
|  | 78 | } | 
|---|
|  | 79 |  | 
|---|
|  | 80 |  | 
|---|
| [2890] | 81 | /** | 
|---|
|  | 82 | * Verbose memcmp(). | 
|---|
|  | 83 | */ | 
|---|
|  | 84 | static int TestMemComp(const void *pv1, const void *pv2, size_t cb) | 
|---|
|  | 85 | { | 
|---|
|  | 86 | size_t          off; | 
|---|
|  | 87 | const uint8_t  *pb1 = (const uint8_t *)pv1; | 
|---|
|  | 88 | const uint8_t  *pb2 = (const uint8_t *)pv2; | 
|---|
|  | 89 | if (!memcmp(pb1, pb2, cb)) | 
|---|
|  | 90 | return 0; | 
|---|
|  | 91 | printf("Mismatching blocks pv1=%p pv2=%p cb=%#x:\n", pv1, pv2, cb); | 
|---|
|  | 92 | for (off = 0; off < cb; off++) | 
|---|
|  | 93 | { | 
|---|
|  | 94 | if (pb1[off] == pb2[off]) | 
|---|
|  | 95 | continue; | 
|---|
|  | 96 | printf("%08x %02x != %02x\n", off, pb1[off], pb2[off]); | 
|---|
|  | 97 | } | 
|---|
|  | 98 | return memcmp(pb1, pb2, cb); /* lazy */ | 
|---|
|  | 99 | } | 
|---|
| [2861] | 100 |  | 
|---|
| [2890] | 101 |  | 
|---|
| [2859] | 102 | /** | 
|---|
| [2861] | 103 | * Performs basic relocation tests. | 
|---|
|  | 104 | */ | 
|---|
|  | 105 | static int BasicTestsRelocate(PKLDRMOD pMod, void *pvBits, void *pvBits2) | 
|---|
|  | 106 | { | 
|---|
|  | 107 | const size_t cbImage = (size_t)kLdrModSize(pMod); | 
|---|
|  | 108 | int rc; | 
|---|
|  | 109 |  | 
|---|
|  | 110 | printf("* Relocation test...\n"); | 
|---|
|  | 111 |  | 
|---|
|  | 112 | /* | 
|---|
|  | 113 | * Get the same bits again to check that we get the same result. | 
|---|
|  | 114 | */ | 
|---|
|  | 115 | memset(pvBits2, 0xfe, cbImage); | 
|---|
|  | 116 | rc = kLdrModGetBits(pMod, pvBits2, (uintptr_t)pvBits, BasicTestsGetImport, NULL); | 
|---|
|  | 117 | if (rc) | 
|---|
| [2955] | 118 | return Failure("failed to get image bits, rc=%d (%s) (a)", rc, kLdrErrStr(rc)); | 
|---|
| [2890] | 119 | if (TestMemComp(pvBits2, pvBits, cbImage)) | 
|---|
| [2861] | 120 | return Failure("relocation test failed, mismatching bits (a)"); | 
|---|
|  | 121 |  | 
|---|
|  | 122 | /* | 
|---|
|  | 123 | * Short relocation round trip. | 
|---|
|  | 124 | */ | 
|---|
|  | 125 | rc = kLdrModRelocateBits(pMod, pvBits2, 0x1000, (uintptr_t)pvBits, BasicTestsGetImport, NULL); | 
|---|
|  | 126 | if (rc) | 
|---|
| [2955] | 127 | return Failure("failed to relocate, rc=%d (%s) (b1)", rc, kLdrErrStr(rc)); | 
|---|
| [2861] | 128 | rc = kLdrModRelocateBits(pMod, pvBits2, (uintptr_t)pvBits, 0x1000, BasicTestsGetImport, NULL); | 
|---|
|  | 129 | if (rc) | 
|---|
| [2955] | 130 | return Failure("failed to relocate, rc=%d (%s) (b2)", rc, kLdrErrStr(rc)); | 
|---|
| [2890] | 131 | if (TestMemComp(pvBits2, pvBits, cbImage)) | 
|---|
| [2861] | 132 | return Failure("relocation test failed, mismatching bits (b)"); | 
|---|
|  | 133 |  | 
|---|
|  | 134 | /* | 
|---|
|  | 135 | * Longer trip where we also check the intermediate results. | 
|---|
|  | 136 | */ | 
|---|
|  | 137 | /* stage one */ | 
|---|
|  | 138 | rc = kLdrModRelocateBits(pMod, pvBits, 0x1000000, (uintptr_t)pvBits, BasicTestsGetImport, NULL); | 
|---|
|  | 139 | if (rc) | 
|---|
| [2955] | 140 | return Failure("failed to relocate, rc=%d (%s) (c1)", rc, kLdrErrStr(rc)); | 
|---|
| [2861] | 141 | memset(pvBits2, 0xfe, cbImage); | 
|---|
|  | 142 | rc = kLdrModGetBits(pMod, pvBits2, 0x1000000, BasicTestsGetImport, NULL); | 
|---|
|  | 143 | if (rc) | 
|---|
| [2955] | 144 | return Failure("failed to get image bits, rc=%d (%s) (c1)", rc, kLdrErrStr(rc)); | 
|---|
| [2890] | 145 | if (TestMemComp(pvBits2, pvBits, cbImage)) | 
|---|
| [2861] | 146 | return Failure("relocation test failed, mismatching bits (c1)"); | 
|---|
|  | 147 |  | 
|---|
|  | 148 | /* stage two */ | 
|---|
|  | 149 | rc = kLdrModRelocateBits(pMod, pvBits, ~(uintptr_t)0x1010000, 0x1000000, BasicTestsGetImport, NULL); | 
|---|
|  | 150 | if (rc) | 
|---|
| [2955] | 151 | return Failure("failed to relocate, rc=%d (%s) (c2)", rc, kLdrErrStr(rc)); | 
|---|
| [2861] | 152 | memset(pvBits2, 0xef, cbImage); | 
|---|
|  | 153 | rc = kLdrModGetBits(pMod, pvBits2, ~(uintptr_t)0x1010000, BasicTestsGetImport, NULL); | 
|---|
|  | 154 | if (rc) | 
|---|
| [2955] | 155 | return Failure("failed to get image bits, rc=%d (%s) (c2)", rc, kLdrErrStr(rc)); | 
|---|
| [2890] | 156 | if (TestMemComp(pvBits2, pvBits, cbImage)) | 
|---|
| [2861] | 157 | return Failure("relocation test failed, mismatching bits (c2)"); | 
|---|
|  | 158 |  | 
|---|
|  | 159 | /* stage three */ | 
|---|
|  | 160 | rc = kLdrModRelocateBits(pMod, pvBits, MY_BASEADDRESS, ~(uintptr_t)0x1010000, BasicTestsGetImport, NULL); | 
|---|
|  | 161 | if (rc) | 
|---|
| [2955] | 162 | return Failure("failed to relocate, rc=%d (%s) (c3)", rc, kLdrErrStr(rc)); | 
|---|
| [2861] | 163 | memset(pvBits2, 0xef, cbImage); | 
|---|
|  | 164 | rc = kLdrModGetBits(pMod, pvBits2, MY_BASEADDRESS, BasicTestsGetImport, NULL); | 
|---|
|  | 165 | if (rc) | 
|---|
| [2955] | 166 | return Failure("failed to get image bits, rc=%d (%s) (c3)", rc, kLdrErrStr(rc)); | 
|---|
| [2890] | 167 | if (TestMemComp(pvBits2, pvBits, cbImage)) | 
|---|
| [2861] | 168 | return Failure("relocation test failed, mismatching bits (c3)"); | 
|---|
|  | 169 |  | 
|---|
|  | 170 | /* stage four */ | 
|---|
|  | 171 | rc = kLdrModRelocateBits(pMod, pvBits, ~(uintptr_t)0 / 2 - 0x10000, MY_BASEADDRESS, BasicTestsGetImport, NULL); | 
|---|
|  | 172 | if (rc) | 
|---|
| [2955] | 173 | return Failure("failed to relocate, rc=%d %(s) (c4)", rc, kLdrErrStr(rc)); | 
|---|
| [2861] | 174 | memset(pvBits2, 0xdc, cbImage); | 
|---|
|  | 175 | rc = kLdrModGetBits(pMod, pvBits2, ~(uintptr_t)0 / 2 - 0x10000, BasicTestsGetImport, NULL); | 
|---|
|  | 176 | if (rc) | 
|---|
| [2955] | 177 | return Failure("failed to get image bits, rc=%d (%s) (c4)", rc, kLdrErrStr(rc)); | 
|---|
| [2890] | 178 | if (TestMemComp(pvBits2, pvBits, cbImage)) | 
|---|
| [2861] | 179 | return Failure("relocation test failed, mismatching bits (c4)"); | 
|---|
|  | 180 |  | 
|---|
|  | 181 | /* return */ | 
|---|
|  | 182 | rc = kLdrModRelocateBits(pMod, pvBits, (uintptr_t)pvBits, ~(uintptr_t)0 / 2 - 0x10000, BasicTestsGetImport, NULL); | 
|---|
|  | 183 | if (rc) | 
|---|
| [2955] | 184 | return Failure("failed to relocate, rc=%d (%s) (c5)", rc, kLdrErrStr(rc)); | 
|---|
| [2861] | 185 | memset(pvBits2, 0xcd, cbImage); | 
|---|
|  | 186 | rc = kLdrModGetBits(pMod, pvBits2, (uintptr_t)pvBits, BasicTestsGetImport, NULL); | 
|---|
|  | 187 | if (rc) | 
|---|
| [2955] | 188 | return Failure("failed to get image bits, rc=%d (%s) (c5)", rc, kLdrErrStr(rc)); | 
|---|
| [2890] | 189 | if (TestMemComp(pvBits2, pvBits, cbImage)) | 
|---|
| [2861] | 190 | return Failure("relocation test failed, mismatching bits (c5)"); | 
|---|
|  | 191 |  | 
|---|
|  | 192 | return 0; | 
|---|
|  | 193 | } | 
|---|
|  | 194 |  | 
|---|
|  | 195 |  | 
|---|
|  | 196 | /** | 
|---|
| [2859] | 197 | * Dump symbols and check that we can query each of them recursivly. | 
|---|
|  | 198 | */ | 
|---|
| [2899] | 199 | static int BasicTestsEnumSymCallback(PKLDRMOD pMod, uint32_t iSymbol, const char *pchSymbol, size_t cchSymbol, | 
|---|
|  | 200 | const char *pszVersion, KLDRADDR uValue, uint32_t fKind, void *pvUser) | 
|---|
| [2859] | 201 | { | 
|---|
|  | 202 | KLDRADDR    uValue2; | 
|---|
|  | 203 | uint32_t    fKind2; | 
|---|
|  | 204 | int         rc; | 
|---|
|  | 205 |  | 
|---|
|  | 206 | /* dump */ | 
|---|
|  | 207 | printf("#0x%08x: %016" PRI_KLDRADDR " %#08x", iSymbol, uValue, fKind); | 
|---|
| [2899] | 208 | if (pchSymbol) | 
|---|
|  | 209 | printf(" %.*s", cchSymbol, pchSymbol); | 
|---|
| [2859] | 210 | printf("\n"); | 
|---|
|  | 211 |  | 
|---|
|  | 212 | /* query by ordinal */ | 
|---|
|  | 213 | if (iSymbol != NIL_KLDRMOD_SYM_ORDINAL) | 
|---|
|  | 214 | { | 
|---|
| [2959] | 215 | fKind2 = 0; | 
|---|
| [2899] | 216 | rc = kLdrModQuerySymbol(pMod, pvUser, MY_BASEADDRESS, iSymbol, NULL, 0, NULL, NULL, NULL, | 
|---|
| [2859] | 217 | &uValue2, &fKind2); | 
|---|
|  | 218 | if (rc) | 
|---|
| [2955] | 219 | return Failure("Couldn't find symbol %#x (%.*s) by ordinal. rc=%d (%s)", iSymbol, cchSymbol, pchSymbol, rc, kLdrErrStr(rc)); | 
|---|
| [2859] | 220 | if (uValue != uValue2) | 
|---|
| [2899] | 221 | return Failure("Symbol %#x (%.*s): Value mismatch %016" PRI_KLDRADDR " != %016" PRI_KLDRADDR " (enum!=query/ord)  pvBits=%p", | 
|---|
|  | 222 | iSymbol, cchSymbol, pchSymbol, uValue, uValue2, pvUser); | 
|---|
| [2859] | 223 | if (fKind != fKind2) | 
|---|
| [2899] | 224 | return Failure("Symbol %#x (%.*s): Kind mismatch %#x != %#x (enum!=query/ord) pvBits=%p", | 
|---|
|  | 225 | iSymbol, cchSymbol, pchSymbol, fKind, fKind2, pvUser); | 
|---|
| [2859] | 226 | } | 
|---|
|  | 227 |  | 
|---|
|  | 228 | /* query by name. */ | 
|---|
| [2899] | 229 | if (pchSymbol) | 
|---|
| [2859] | 230 | { | 
|---|
| [2959] | 231 | fKind2 = 0; | 
|---|
| [2899] | 232 | rc = kLdrModQuerySymbol(pMod, pvUser, MY_BASEADDRESS, NIL_KLDRMOD_SYM_ORDINAL, pchSymbol, cchSymbol, pszVersion, | 
|---|
|  | 233 | NULL, NULL, &uValue2, &fKind2); | 
|---|
| [2859] | 234 | if (rc) | 
|---|
| [2955] | 235 | return Failure("Couldn't find symbol %#x (%.*s) by name. rc=%d (%s)", iSymbol, cchSymbol, pchSymbol, rc, kLdrErrStr(rc)); | 
|---|
| [2859] | 236 | if (uValue != uValue2) | 
|---|
| [2899] | 237 | return Failure("Symbol %#x (%.*s): Value mismatch %016" PRI_KLDRADDR " != %016" PRI_KLDRADDR " (enum!=query/name) pvBits=%p", | 
|---|
|  | 238 | iSymbol, cchSymbol, pchSymbol, uValue, uValue2, pvUser); | 
|---|
| [2859] | 239 | if (fKind != fKind2) | 
|---|
| [2899] | 240 | return Failure("Symbol %#x (%.*s): Kind mismatch %#x != %#x (enum!=query/name) pvBits=%p", | 
|---|
|  | 241 | iSymbol, cchSymbol, pchSymbol, fKind, fKind2, pvUser); | 
|---|
| [2859] | 242 | } | 
|---|
|  | 243 |  | 
|---|
|  | 244 | return 0; | 
|---|
|  | 245 | } | 
|---|
|  | 246 |  | 
|---|
|  | 247 |  | 
|---|
|  | 248 | /** | 
|---|
|  | 249 | * Dump debugger information and check it for correctness. | 
|---|
|  | 250 | */ | 
|---|
|  | 251 | static int BasicTestEnumDbgInfoCallback(PKLDRMOD pMod, uint32_t iDbgInfo, KLDRDBGINFOTYPE enmType, | 
|---|
| [2974] | 252 | int16_t iMajorVer, int16_t iMinorVer, KLDRFOFF offFile, KLDRADDR LinkAddress, | 
|---|
| [2859] | 253 | KLDRSIZE cb, const char *pszExtFile, void *pvUser) | 
|---|
|  | 254 | { | 
|---|
|  | 255 | printf("#0x%08x: enmType=%d %d.%d offFile=0x%" PRI_KLDRADDR " LinkAddress=%" PRI_KLDRADDR " cb=%" PRI_KLDRSIZE " pvUser=%p\n", | 
|---|
|  | 256 | iDbgInfo, enmType, iMajorVer, iMinorVer, (KLDRADDR)offFile, LinkAddress, cb, pvUser); | 
|---|
|  | 257 | if (pszExtFile) | 
|---|
|  | 258 | printf("            pszExtFile=%p '%s'\n", pszExtFile, pszExtFile); | 
|---|
|  | 259 |  | 
|---|
|  | 260 | if (enmType >= KLDRDBGINFOTYPE_END || enmType <= KLDRDBGINFOTYPE_INVALID) | 
|---|
|  | 261 | return Failure("Bad enmType"); | 
|---|
|  | 262 | if (pvUser != NULL) | 
|---|
|  | 263 | return Failure("pvUser"); | 
|---|
|  | 264 |  | 
|---|
|  | 265 | return 0; | 
|---|
|  | 266 | } | 
|---|
|  | 267 |  | 
|---|
|  | 268 |  | 
|---|
|  | 269 | /** | 
|---|
|  | 270 | * Performs the basic module loader test on the specified module and image bits. | 
|---|
|  | 271 | */ | 
|---|
|  | 272 | static int BasicTestsSub2(PKLDRMOD pMod, void *pvBits) | 
|---|
|  | 273 | { | 
|---|
|  | 274 | int32_t cImports; | 
|---|
|  | 275 | int32_t i; | 
|---|
|  | 276 | int rc; | 
|---|
|  | 277 | uint32_t fKind; | 
|---|
|  | 278 | KLDRADDR Value; | 
|---|
|  | 279 | KLDRADDR MainEPAddress; | 
|---|
|  | 280 | KLDRSTACKINFO StackInfo; | 
|---|
|  | 281 |  | 
|---|
| [2861] | 282 | printf("* Testing queries with pvBits=%p...\n", pvBits); | 
|---|
|  | 283 |  | 
|---|
| [2859] | 284 | /* | 
|---|
|  | 285 | * Get the import modules. | 
|---|
|  | 286 | */ | 
|---|
|  | 287 | cImports = kLdrModNumberOfImports(pMod, pvBits); | 
|---|
|  | 288 | printf("cImports=%d\n", cImports); | 
|---|
|  | 289 | if (cImports < 0) | 
|---|
| [2861] | 290 | return Failure("failed to query the number of import, cImports=%d", cImports); | 
|---|
| [2859] | 291 | for (i = 0; i < cImports; i++) | 
|---|
|  | 292 | { | 
|---|
|  | 293 | char szImportModule[260]; | 
|---|
|  | 294 | rc = kLdrModGetImport(pMod, pvBits, i, szImportModule, sizeof(szImportModule)); | 
|---|
|  | 295 | if (rc) | 
|---|
| [2955] | 296 | return Failure("failed to get import module name, rc=%d (%s). (%.260s)", rc, kLdrErrStr(rc), szImportModule); | 
|---|
| [2859] | 297 | printf("import #%d: '%s'\n", i, szImportModule); | 
|---|
|  | 298 | } | 
|---|
|  | 299 |  | 
|---|
|  | 300 | /* | 
|---|
|  | 301 | * Query stack info. | 
|---|
|  | 302 | */ | 
|---|
|  | 303 | StackInfo.Address = ~(KLDRADDR)42; | 
|---|
|  | 304 | StackInfo.LinkAddress = ~(KLDRADDR)42; | 
|---|
|  | 305 | StackInfo.cbStack = ~(KLDRSIZE)42; | 
|---|
|  | 306 | StackInfo.cbStackThread = ~(KLDRSIZE)42; | 
|---|
|  | 307 | rc = kLdrModGetStackInfo(pMod, pvBits, MY_BASEADDRESS, &StackInfo); | 
|---|
|  | 308 | if (rc) | 
|---|
| [2955] | 309 | return Failure("kLdrModGetStackInfo failed with rc=%d (%s)", rc, kLdrErrStr(rc)); | 
|---|
| [2859] | 310 | printf("Stack: Address=%016" PRI_KLDRADDR "   LinkAddress=%016" PRI_KLDRADDR "\n" | 
|---|
|  | 311 | "       cbStack=%016" PRI_KLDRSIZE " cbStackThread=%016" PRI_KLDRSIZE "\n", | 
|---|
|  | 312 | StackInfo.Address, StackInfo.LinkAddress, StackInfo.cbStack, StackInfo.cbStackThread); | 
|---|
|  | 313 | if (StackInfo.Address == ~(KLDRADDR)42) | 
|---|
|  | 314 | return Failure("Bad StackInfo.Address"); | 
|---|
|  | 315 | if (StackInfo.LinkAddress == ~(KLDRADDR)42) | 
|---|
|  | 316 | return Failure("Bad StackInfo.LinkAddress"); | 
|---|
|  | 317 | if (StackInfo.cbStack == ~(KLDRSIZE)42) | 
|---|
|  | 318 | return Failure("Bad StackInfo.cbStack"); | 
|---|
|  | 319 | if (StackInfo.cbStackThread == ~(KLDRSIZE)42) | 
|---|
|  | 320 | return Failure("Bad StackInfo.cbStackThread"); | 
|---|
|  | 321 |  | 
|---|
|  | 322 | /* | 
|---|
|  | 323 | * Query entrypoint. | 
|---|
|  | 324 | */ | 
|---|
|  | 325 | MainEPAddress = ~(KLDRADDR)42; | 
|---|
|  | 326 | rc = kLdrModQueryMainEntrypoint(pMod, pvBits, MY_BASEADDRESS, &MainEPAddress); | 
|---|
|  | 327 | if (rc) | 
|---|
| [2955] | 328 | return Failure("kLdrModQueryMainEntrypoint failed with rc=%d (%s)", rc, kLdrErrStr(rc)); | 
|---|
| [2859] | 329 | printf("Entrypoint: %016" PRI_KLDRADDR "\n", MainEPAddress); | 
|---|
|  | 330 | if (MainEPAddress == ~(KLDRADDR)42) | 
|---|
|  | 331 | return Failure("MainEPAddress wasn't set."); | 
|---|
| [2861] | 332 | if (MainEPAddress != NIL_KLDRADDR && MainEPAddress < MY_BASEADDRESS) | 
|---|
|  | 333 | return Failure("Bad MainEPAddress (a)."); | 
|---|
|  | 334 | if (MainEPAddress != NIL_KLDRADDR && MainEPAddress >= MY_BASEADDRESS + kLdrModSize(pMod)) | 
|---|
|  | 335 | return Failure("Bad MainEPAddress (b)."); | 
|---|
| [2859] | 336 |  | 
|---|
|  | 337 | /* | 
|---|
|  | 338 | * Debugger information. | 
|---|
|  | 339 | */ | 
|---|
|  | 340 | rc = kLdrModHasDbgInfo(pMod, pvBits); | 
|---|
|  | 341 | if (!rc) | 
|---|
|  | 342 | printf("Has Debugger Information\n"); | 
|---|
|  | 343 | else if (rc == KLDR_ERR_NO_DEBUG_INFO) | 
|---|
|  | 344 | printf("NO Debugger Information\n"); | 
|---|
|  | 345 | else | 
|---|
| [2955] | 346 | return Failure("kLdrModHasDbgInfo failed with rc=%d (%s)", rc, kLdrErrStr(rc)); | 
|---|
| [2859] | 347 | rc = kLdrModEnumDbgInfo(pMod, pvBits, BasicTestEnumDbgInfoCallback, NULL); | 
|---|
|  | 348 | if (rc) | 
|---|
| [2955] | 349 | return Failure("kLdrModEnumDbgInfo failed with rc=%d (%s)", rc, kLdrErrStr(rc)); | 
|---|
| [2859] | 350 |  | 
|---|
|  | 351 |  | 
|---|
|  | 352 | /* | 
|---|
|  | 353 | * Negative symbol query tests. | 
|---|
|  | 354 | */ | 
|---|
| [2959] | 355 | fKind = 0; | 
|---|
| [2859] | 356 | Value = 0x0badc0de; | 
|---|
| [2899] | 357 | rc = kLdrModQuerySymbol(pMod, pvBits, MY_BASEADDRESS, NIL_KLDRMOD_SYM_ORDINAL - 20, NULL, 0, NULL, NULL, NULL, | 
|---|
| [2859] | 358 | &Value, &fKind); | 
|---|
|  | 359 | if (rc) | 
|---|
|  | 360 | { | 
|---|
|  | 361 | if (Value != 0) | 
|---|
|  | 362 | return Failure("Value wasn't cleared on failure."); | 
|---|
|  | 363 | } | 
|---|
|  | 364 |  | 
|---|
| [2959] | 365 | fKind = 0; | 
|---|
| [2859] | 366 | Value = 0x0badc0de; | 
|---|
| [2899] | 367 | rc = kLdrModQuerySymbol(pMod, pvBits, MY_BASEADDRESS, NIL_KLDRMOD_SYM_ORDINAL, NULL, 0, NULL, NULL, NULL, | 
|---|
| [2859] | 368 | &Value, &fKind); | 
|---|
|  | 369 | if (!rc) | 
|---|
|  | 370 | return Failure("NIL ordinal succeeded!"); | 
|---|
|  | 371 | if (Value != 0) | 
|---|
|  | 372 | return Failure("Value wasn't cleared on failure."); | 
|---|
|  | 373 |  | 
|---|
|  | 374 | /* | 
|---|
|  | 375 | * Enumerate and query all symbols. | 
|---|
|  | 376 | */ | 
|---|
|  | 377 | printf("\n" | 
|---|
|  | 378 | "Symbols:\n"); | 
|---|
|  | 379 | rc = kLdrModEnumSymbols(pMod, pvBits, MY_BASEADDRESS, 0, BasicTestsEnumSymCallback, pvBits); | 
|---|
|  | 380 | if (rc) | 
|---|
| [2955] | 381 | return Failure("kLdrModEnumSymbols failed with rc=%d (%s)", rc, kLdrErrStr(rc)); | 
|---|
| [2859] | 382 |  | 
|---|
|  | 383 |  | 
|---|
|  | 384 | /*int     kLdrModCanExecuteOn(PKLDRMOD pMod, const void *pvBits, KLDRARCH enmArch, KLDRCPU enmCpu); | 
|---|
|  | 385 | */ | 
|---|
|  | 386 |  | 
|---|
|  | 387 | return 0; | 
|---|
|  | 388 | } | 
|---|
|  | 389 |  | 
|---|
|  | 390 |  | 
|---|
|  | 391 | /** | 
|---|
|  | 392 | * Performs the basic module loader test on the specified module | 
|---|
|  | 393 | */ | 
|---|
|  | 394 | static int BasicTestsSub(PKLDRMOD pMod) | 
|---|
|  | 395 | { | 
|---|
|  | 396 | int         rc; | 
|---|
|  | 397 | uint32_t    i; | 
|---|
|  | 398 | void       *pvBits; | 
|---|
|  | 399 | size_t      cbImage; | 
|---|
|  | 400 |  | 
|---|
|  | 401 | /* | 
|---|
|  | 402 | * Check/dump the module structure. | 
|---|
|  | 403 | */ | 
|---|
| [2899] | 404 | printf("pMod=%p u32Magic=%#x cSegments=%d\n", (void *)pMod, pMod->u32Magic, pMod->cSegments); | 
|---|
| [2859] | 405 | printf("enmType=%d enmFmt=%d enmArch=%d enmCpu=%d enmEndian=%d\n", | 
|---|
|  | 406 | pMod->enmType, pMod->enmFmt, pMod->enmArch, pMod->enmCpu, pMod->enmEndian); | 
|---|
|  | 407 | printf("Filename: %s (%d bytes)\n", pMod->pszFilename, pMod->cchFilename); | 
|---|
|  | 408 | printf("    Name: %s (%d bytes)\n", pMod->pszName, pMod->cchName); | 
|---|
|  | 409 | printf("\n"); | 
|---|
|  | 410 |  | 
|---|
|  | 411 | if (pMod->u32Magic != KLDRMOD_MAGIC) | 
|---|
|  | 412 | return Failure("Bad u32Magic"); | 
|---|
|  | 413 | if (strlen(pMod->pszFilename) != pMod->cchFilename) | 
|---|
|  | 414 | return Failure("Bad cchFilename"); | 
|---|
|  | 415 | if (strlen(pMod->pszName) != pMod->cchName) | 
|---|
|  | 416 | return Failure("Bad cchName"); | 
|---|
|  | 417 | if (pMod->enmFmt >= KLDRFMT_END || pMod->enmFmt <= KLDRFMT_INVALID) | 
|---|
|  | 418 | return Failure("Bad enmFmt"); | 
|---|
|  | 419 | if (pMod->enmType >= KLDRTYPE_END || pMod->enmType <= KLDRTYPE_INVALID) | 
|---|
|  | 420 | return Failure("Bad enmType: %d", pMod->enmType); | 
|---|
|  | 421 | if (pMod->enmArch >= KLDRARCH_END || pMod->enmArch <= KLDRARCH_INVALID) | 
|---|
|  | 422 | return Failure("Bad enmArch"); | 
|---|
|  | 423 | if (pMod->enmCpu >= KLDRCPU_END || pMod->enmCpu <= KLDRCPU_INVALID) | 
|---|
|  | 424 | return Failure("Bad enmCpu"); | 
|---|
|  | 425 | if (pMod->enmEndian >= KLDRENDIAN_END || pMod->enmEndian <= KLDRENDIAN_INVALID) | 
|---|
|  | 426 | return Failure("Bad enmEndian"); | 
|---|
|  | 427 |  | 
|---|
|  | 428 | for (i = 0; i < pMod->cSegments; i++) | 
|---|
|  | 429 | { | 
|---|
|  | 430 | printf("seg #%d: pvUser=%p enmProt=%d Name: '%.*s' (%d bytes)\n", | 
|---|
|  | 431 | i, pMod->aSegments[i].pvUser, pMod->aSegments[i].enmProt, | 
|---|
|  | 432 | pMod->aSegments[i].cchName, pMod->aSegments[i].pchName, pMod->aSegments[i].cchName); | 
|---|
|  | 433 | printf("LinkAddress: %016" PRI_KLDRADDR "       cb: %016" PRI_KLDRSIZE "  Alignment=%08" PRI_KLDRADDR " \n", | 
|---|
|  | 434 | pMod->aSegments[i].LinkAddress, pMod->aSegments[i].cb, pMod->aSegments[i].Alignment); | 
|---|
|  | 435 | printf("        RVA: %016" PRI_KLDRADDR " cbMapped: %016" PRI_KLDRSIZE " MapAddress=%p\n", | 
|---|
| [2899] | 436 | pMod->aSegments[i].RVA, (KLDRSIZE)pMod->aSegments[i].cbMapped, (void *)pMod->aSegments[i].MapAddress); | 
|---|
| [2859] | 437 | printf("    offFile: %016" PRI_KLDRADDR "   cbFile: %016" PRI_KLDRSIZE "\n", | 
|---|
|  | 438 | (KLDRADDR)pMod->aSegments[i].offFile, (KLDRSIZE)pMod->aSegments[i].cbFile); | 
|---|
|  | 439 | printf("\n"); | 
|---|
|  | 440 |  | 
|---|
|  | 441 | if (pMod->aSegments[i].pvUser != NULL) | 
|---|
|  | 442 | return Failure("Bad pvUser"); | 
|---|
|  | 443 | if (pMod->aSegments[i].enmProt >= KLDRPROT_END || pMod->aSegments[i].enmProt <= KLDRPROT_INVALID) | 
|---|
|  | 444 | return Failure("Bad enmProt"); | 
|---|
|  | 445 | if (pMod->aSegments[i].MapAddress != 0) | 
|---|
|  | 446 | return Failure("Bad MapAddress"); | 
|---|
|  | 447 | if (pMod->aSegments[i].cbMapped < pMod->aSegments[i].cb) | 
|---|
|  | 448 | return Failure("Bad cbMapped (1)"); | 
|---|
|  | 449 | if (pMod->aSegments[i].cbMapped && !pMod->aSegments[i].Alignment) | 
|---|
|  | 450 | return Failure("Bad cbMapped (2)"); | 
|---|
|  | 451 | if (pMod->aSegments[i].cbMapped > kLdrModSize(pMod)) | 
|---|
|  | 452 | return Failure("Bad cbMapped (3)"); | 
|---|
|  | 453 | if (    pMod->aSegments[i].Alignment | 
|---|
|  | 454 | &&  (pMod->aSegments[i].RVA & (pMod->aSegments[i].Alignment - 1))) | 
|---|
|  | 455 | return Failure("Bad RVA (1)"); | 
|---|
|  | 456 | if (pMod->aSegments[i].RVA != NIL_KLDRADDR && !pMod->aSegments[i].Alignment) | 
|---|
|  | 457 | return Failure("Bad RVA (2)"); | 
|---|
|  | 458 | if (    pMod->aSegments[i].RVA != NIL_KLDRADDR | 
|---|
|  | 459 | &&  pMod->aSegments[i].RVA >= kLdrModSize(pMod)) | 
|---|
|  | 460 | return Failure("Bad RVA (3)"); | 
|---|
|  | 461 | if (    pMod->aSegments[i].RVA != NIL_KLDRADDR | 
|---|
|  | 462 | &&  pMod->aSegments[i].RVA + pMod->aSegments[i].cbMapped > kLdrModSize(pMod)) | 
|---|
|  | 463 | return Failure("Bad RVA/cbMapped (4)"); | 
|---|
|  | 464 | if (pMod->aSegments[i].LinkAddress != NIL_KLDRADDR && !pMod->aSegments[i].Alignment) | 
|---|
|  | 465 | return Failure("Bad LinkAddress"); | 
|---|
|  | 466 | if (    pMod->aSegments[i].LinkAddress != NIL_KLDRADDR | 
|---|
|  | 467 | &&  (pMod->aSegments[i].LinkAddress) & (pMod->aSegments[i].Alignment - 1)) | 
|---|
|  | 468 | return Failure("Bad LinkAddress alignment"); | 
|---|
|  | 469 | if (pMod->aSegments[i].offFile != -1 && pMod->aSegments[i].cbFile == -1) | 
|---|
|  | 470 | return Failure("Bad offFile"); | 
|---|
|  | 471 | if (pMod->aSegments[i].offFile == -1 && pMod->aSegments[i].cbFile != -1) | 
|---|
|  | 472 | return Failure("Bad cbFile"); | 
|---|
|  | 473 | } | 
|---|
|  | 474 |  | 
|---|
| [2861] | 475 |  | 
|---|
| [2859] | 476 | /* | 
|---|
|  | 477 | * Get image the size and query the image bits. | 
|---|
|  | 478 | */ | 
|---|
| [2861] | 479 | printf("* Testing user mapping...\n"); | 
|---|
|  | 480 |  | 
|---|
| [2859] | 481 | cbImage = (size_t)kLdrModSize(pMod); | 
|---|
|  | 482 | if (cbImage != kLdrModSize(pMod)) | 
|---|
| [2861] | 483 | return Failure("aborting test because the image is too huge!"); | 
|---|
| [2859] | 484 | pvBits = malloc((size_t)cbImage); | 
|---|
|  | 485 | if (!pvBits) | 
|---|
| [2861] | 486 | return Failure("failed to allocate %d bytes for the image", cbImage); | 
|---|
| [2859] | 487 |  | 
|---|
|  | 488 | rc = kLdrModGetBits(pMod, pvBits, (uintptr_t)pvBits, BasicTestsGetImport, NULL); | 
|---|
|  | 489 | if (rc) | 
|---|
| [2955] | 490 | return Failure("failed to get image bits, rc=%d (%s)", rc, kLdrErrStr(rc)); | 
|---|
| [2859] | 491 |  | 
|---|
|  | 492 | /* | 
|---|
|  | 493 | * Another cleanup nesting. | 
|---|
|  | 494 | */ | 
|---|
|  | 495 | rc = BasicTestsSub2(pMod, pvBits); | 
|---|
| [2861] | 496 | if (!rc) | 
|---|
|  | 497 | { | 
|---|
|  | 498 | /* | 
|---|
|  | 499 | * Test relocating the bits in a few different ways before we're done with them. | 
|---|
|  | 500 | */ | 
|---|
|  | 501 | void *pvBits2 = malloc((size_t)cbImage); | 
|---|
|  | 502 | if (pvBits2) | 
|---|
|  | 503 | { | 
|---|
|  | 504 | rc = BasicTestsRelocate(pMod, pvBits, pvBits2); | 
|---|
|  | 505 | free(pvBits2); | 
|---|
|  | 506 | } | 
|---|
|  | 507 | else | 
|---|
|  | 508 | rc = Failure("failed to allocate %d bytes for the 2nd image", cbImage); | 
|---|
|  | 509 | } | 
|---|
|  | 510 |  | 
|---|
| [2859] | 511 | free(pvBits); | 
|---|
|  | 512 | return rc; | 
|---|
|  | 513 | } | 
|---|
|  | 514 |  | 
|---|
|  | 515 |  | 
|---|
|  | 516 | /** | 
|---|
| [2861] | 517 | * Tests the mapping related api, after mapping. | 
|---|
|  | 518 | */ | 
|---|
|  | 519 | static int BasicTestsSubMap2(PKLDRMOD pMod) | 
|---|
|  | 520 | { | 
|---|
|  | 521 | int rc; | 
|---|
|  | 522 |  | 
|---|
|  | 523 | rc = kLdrModFixupMapping(pMod, BasicTestsGetImport, NULL); | 
|---|
|  | 524 | if (rc) | 
|---|
| [2955] | 525 | return Failure("kLdrModFixupMapping (a) failed, rc=%d (%s)", rc, kLdrErrStr(rc)); | 
|---|
| [2861] | 526 |  | 
|---|
|  | 527 | rc = kLdrModReload(pMod); | 
|---|
|  | 528 | if (rc) | 
|---|
| [2955] | 529 | return Failure("kLdrModReload (a) failed, rc=%d (%s)", rc, kLdrErrStr(rc)); | 
|---|
| [2861] | 530 |  | 
|---|
|  | 531 | rc = kLdrModReload(pMod); | 
|---|
|  | 532 | if (rc) | 
|---|
| [2955] | 533 | return Failure("kLdrModReload (b) failed, rc=%d (%s)", rc, kLdrErrStr(rc)); | 
|---|
| [2861] | 534 |  | 
|---|
|  | 535 | rc = kLdrModFixupMapping(pMod, BasicTestsGetImport, NULL); | 
|---|
|  | 536 | if (rc) | 
|---|
| [2955] | 537 | return Failure("kLdrModFixupMapping (b) failed, rc=%d (%s)", rc, kLdrErrStr(rc)); | 
|---|
| [2861] | 538 |  | 
|---|
|  | 539 | rc = kLdrModAllocTLS(pMod); | 
|---|
|  | 540 | if (rc) | 
|---|
| [2955] | 541 | return Failure("kLdrModAllocTLS (a) failed, rc=%d (%s)", rc, kLdrErrStr(rc)); | 
|---|
| [2861] | 542 | kLdrModFreeTLS(pMod); | 
|---|
|  | 543 |  | 
|---|
|  | 544 | rc = kLdrModAllocTLS(pMod); | 
|---|
|  | 545 | if (rc) | 
|---|
| [2955] | 546 | return Failure("kLdrModAllocTLS (b) failed, rc=%d (%s)", rc, kLdrErrStr(rc)); | 
|---|
| [2861] | 547 | kLdrModFreeTLS(pMod); | 
|---|
|  | 548 |  | 
|---|
|  | 549 | /* | 
|---|
|  | 550 | * Repeat the BasicTestsSub2 with pvBits as NULL to test module | 
|---|
|  | 551 | * interpreters that can utilize the mapping. | 
|---|
|  | 552 | */ | 
|---|
|  | 553 | rc = BasicTestsSub2(pMod, NULL); | 
|---|
|  | 554 | if (rc) | 
|---|
| [2955] | 555 | return Failure("BasicTestsSub2 in Map2 failed, rc=%d (%s)", rc, kLdrErrStr(rc)); | 
|---|
| [2861] | 556 | return 0; | 
|---|
|  | 557 | } | 
|---|
|  | 558 |  | 
|---|
|  | 559 |  | 
|---|
|  | 560 | /** | 
|---|
| [2860] | 561 | * Tests the mapping related api. | 
|---|
|  | 562 | */ | 
|---|
|  | 563 | static int BasicTestsSubMap(PKLDRMOD pMod) | 
|---|
|  | 564 | { | 
|---|
| [2861] | 565 | int rc, rc2; | 
|---|
|  | 566 | printf("* Mapping tests...\n"); | 
|---|
| [2860] | 567 |  | 
|---|
|  | 568 | rc = kLdrModMap(pMod); | 
|---|
|  | 569 | if (rc) | 
|---|
| [2955] | 570 | return Failure("kLdrModMap failed, rc=%d (%s)", rc, kLdrErrStr(rc)); | 
|---|
| [2861] | 571 | rc = BasicTestsSubMap2(pMod); | 
|---|
|  | 572 | rc2 = kLdrModUnmap(pMod); | 
|---|
|  | 573 | if (rc2) | 
|---|
|  | 574 | { | 
|---|
| [2955] | 575 | Failure("kLdrModUnmap failed, rc=%d (%s)", rc2, kLdrErrStr(rc2)); | 
|---|
| [2861] | 576 | rc = rc ? rc : rc2; | 
|---|
|  | 577 | } | 
|---|
| [2860] | 578 |  | 
|---|
| [2861] | 579 | printf("* Mapping tests done.\n"); | 
|---|
|  | 580 | return rc; | 
|---|
| [2860] | 581 | } | 
|---|
|  | 582 |  | 
|---|
|  | 583 |  | 
|---|
|  | 584 | /** | 
|---|
| [2859] | 585 | * Performs basic module loader tests on the specified file. | 
|---|
|  | 586 | */ | 
|---|
|  | 587 | static int BasicTests(const char *pszFilename) | 
|---|
|  | 588 | { | 
|---|
|  | 589 | PKLDRMOD pMod; | 
|---|
|  | 590 | int rc, rc2; | 
|---|
|  | 591 |  | 
|---|
| [2861] | 592 | printf("tstLdrMod: Testing '%s'", pszFilename); | 
|---|
| [2859] | 593 | rc = kLdrModOpen(pszFilename, &pMod); | 
|---|
|  | 594 | if (!rc) | 
|---|
|  | 595 | { | 
|---|
|  | 596 | rc = BasicTestsSub(pMod); | 
|---|
| [2860] | 597 | if (!rc) | 
|---|
|  | 598 | rc = BasicTestsSubMap(pMod); | 
|---|
| [2861] | 599 | if (!rc) | 
|---|
|  | 600 | rc = BasicTestsSub2(pMod, NULL); | 
|---|
| [2859] | 601 | rc2 = kLdrModClose(pMod); | 
|---|
|  | 602 | if (rc2) | 
|---|
| [2955] | 603 | Failure("failed to close '%s', rc=%d (%s)", pszFilename, rc, kLdrErrStr(rc)); | 
|---|
| [2859] | 604 | if (rc2 && !rc) | 
|---|
|  | 605 | rc = rc2; | 
|---|
|  | 606 | } | 
|---|
|  | 607 | else | 
|---|
| [2955] | 608 | Failure("Failed to open '%s', rc=%d (%s)", pszFilename, rc, kLdrErrStr(rc)); | 
|---|
| [2859] | 609 | return rc ? 1 : 0; | 
|---|
|  | 610 | } | 
|---|
|  | 611 |  | 
|---|
|  | 612 |  | 
|---|
|  | 613 | int main(int argc, char **argv) | 
|---|
|  | 614 | { | 
|---|
|  | 615 | BasicTests(argv[argc-1]); | 
|---|
|  | 616 |  | 
|---|
|  | 617 | if (!g_cErrors) | 
|---|
|  | 618 | printf("tstLdrMod: SUCCESS\n"); | 
|---|
|  | 619 | else | 
|---|
|  | 620 | printf("tstLdrMod: FAILURE - %d errors\n", g_cErrors); | 
|---|
|  | 621 | return !!g_cErrors; | 
|---|
|  | 622 | } | 
|---|
|  | 623 |  | 
|---|