| 1 | /* $Id: dbgLXDumper.c,v 1.1 2000-03-24 18:13:44 bird Exp $
|
|---|
| 2 | *
|
|---|
| 3 | * dbgLXDumper - reads and interprets the debuginfo found in an LX executable.
|
|---|
| 4 | *
|
|---|
| 5 | * Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
|
|---|
| 6 | *
|
|---|
| 7 | * Project Odin Software License can be found in LICENSE.TXT
|
|---|
| 8 | *
|
|---|
| 9 | */
|
|---|
| 10 |
|
|---|
| 11 | /*******************************************************************************
|
|---|
| 12 | * Defined Constants And Macros *
|
|---|
| 13 | *******************************************************************************/
|
|---|
| 14 | #define INCL_TYPES
|
|---|
| 15 | #define INCL_DOSERRORS
|
|---|
| 16 | #define FOR_EXEHDR 1 /* exe386.h flag */
|
|---|
| 17 | #define DWORD ULONG
|
|---|
| 18 | #define WORD USHORT
|
|---|
| 19 |
|
|---|
| 20 | /*******************************************************************************
|
|---|
| 21 | * Header Files *
|
|---|
| 22 | *******************************************************************************/
|
|---|
| 23 | #include <os2.h>
|
|---|
| 24 | #include <newexe.h>
|
|---|
| 25 | #include <exe386.h>
|
|---|
| 26 | #include <string.h>
|
|---|
| 27 | #include <stdio.h>
|
|---|
| 28 | #include <malloc.h>
|
|---|
| 29 | #include <ctype.h>
|
|---|
| 30 |
|
|---|
| 31 | #include "hll.h"
|
|---|
| 32 |
|
|---|
| 33 |
|
|---|
| 34 |
|
|---|
| 35 | /*******************************************************************************
|
|---|
| 36 | * Internal Functions *
|
|---|
| 37 | *******************************************************************************/
|
|---|
| 38 | static int dbgLXDump(void *pvFile);
|
|---|
| 39 | static int dumpHLL(FILE *phOut, PBYTE pb, int cb);
|
|---|
| 40 | static void dumpHex(FILE *phOut, PBYTE pb, int cb);
|
|---|
| 41 | static void * readfile(const char *pszFilename);
|
|---|
| 42 | static signed long fsize(FILE *phFile);
|
|---|
| 43 |
|
|---|
| 44 |
|
|---|
| 45 |
|
|---|
| 46 |
|
|---|
| 47 |
|
|---|
| 48 | int main(int argc, char **argv)
|
|---|
| 49 | {
|
|---|
| 50 | void * pvFile;
|
|---|
| 51 |
|
|---|
| 52 | if (argc != 2)
|
|---|
| 53 | {
|
|---|
| 54 | fprintf(stderr, "error parameters!\n");
|
|---|
| 55 | return -1;
|
|---|
| 56 | }
|
|---|
| 57 |
|
|---|
| 58 | pvFile = readfile(argv[1]);
|
|---|
| 59 | if (pvFile == NULL)
|
|---|
| 60 | {
|
|---|
| 61 | fprintf(stderr, "error reading file %s\n", argv[1]);
|
|---|
| 62 | return -2;
|
|---|
| 63 | }
|
|---|
| 64 |
|
|---|
| 65 | return dbgLXDump(pvFile);
|
|---|
| 66 | }
|
|---|
| 67 |
|
|---|
| 68 |
|
|---|
| 69 |
|
|---|
| 70 | /**
|
|---|
| 71 | * Dumps the internals of LX dubug info.
|
|---|
| 72 | * @returns error code. (0 is ok)
|
|---|
| 73 | * @param pvFile Pointer to filemapping.
|
|---|
| 74 | * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
|
|---|
| 75 | */
|
|---|
| 76 | static int dbgLXDump(void *pvFile)
|
|---|
| 77 | {
|
|---|
| 78 | struct exe_hdr * pehdr = (struct exe_hdr *) pvFile;
|
|---|
| 79 | struct e32_exe * pe32;
|
|---|
| 80 | unsigned offe32;
|
|---|
| 81 | PBYTE pbFile = (PBYTE)pvFile;
|
|---|
| 82 |
|
|---|
| 83 | /*
|
|---|
| 84 | * Find LX header.
|
|---|
| 85 | */
|
|---|
| 86 | if (pehdr->e_magic == EMAGIC)
|
|---|
| 87 | offe32 = pehdr->e_lfanew;
|
|---|
| 88 | else
|
|---|
| 89 | offe32 = 0;
|
|---|
| 90 | pe32 = (struct e32_exe *)((unsigned)pvFile + offe32);
|
|---|
| 91 | if (pe32->e32_magic[0] != E32MAGIC1 || pe32->e32_magic[1] != E32MAGIC2)
|
|---|
| 92 | {
|
|---|
| 93 | fprintf(stderr, "not LX executable\n");
|
|---|
| 94 | return ERROR_INVALID_EXE_SIGNATURE;
|
|---|
| 95 | }
|
|---|
| 96 |
|
|---|
| 97 | /*
|
|---|
| 98 | * Check if there is any debuginfo in this executable.
|
|---|
| 99 | */
|
|---|
| 100 | printf("e32_debuginfo 0x%08x (%d)\n"
|
|---|
| 101 | "e32_debuglen 0x%08x (%d)\n",
|
|---|
| 102 | pe32->e32_debuginfo, pe32->e32_debuglen);
|
|---|
| 103 |
|
|---|
| 104 | if (pe32->e32_debuginfo != 0 && pe32->e32_debuglen > 0)
|
|---|
| 105 | {
|
|---|
| 106 | PBYTE pbDbg = pbFile + pe32->e32_debuginfo;
|
|---|
| 107 | /*
|
|---|
| 108 | * Check signature. 'NB0'
|
|---|
| 109 | */
|
|---|
| 110 | printf("Debug signature: %c%c%c%c\n",
|
|---|
| 111 | pbDbg[0], pbDbg[1], pbDbg[2], pbDbg[3]);
|
|---|
| 112 | if (pbDbg[0] == 'N' && pbDbg[1] == 'B' && pbDbg[2] == '0')
|
|---|
| 113 | {
|
|---|
| 114 | int i;
|
|---|
| 115 |
|
|---|
| 116 | /*
|
|---|
| 117 | * Switch on debug datatype.
|
|---|
| 118 | */
|
|---|
| 119 | switch (pbDbg[3])
|
|---|
| 120 | {
|
|---|
| 121 | case '0':
|
|---|
| 122 | printf("Found 32-bit Codeview format\n");
|
|---|
| 123 | break;
|
|---|
| 124 |
|
|---|
| 125 | case '1':
|
|---|
| 126 | printf("Found AIX Debugger format - unsupported\n");
|
|---|
| 127 | break;
|
|---|
| 128 |
|
|---|
| 129 | case '2':
|
|---|
| 130 | printf("Found 16-bit Codeview format\n");
|
|---|
| 131 | break;
|
|---|
| 132 |
|
|---|
| 133 | case '4':
|
|---|
| 134 | printf("Found 32-bit OS/2 PM Debugger format (HLL)\n");
|
|---|
| 135 | return dumpHLL(stdout, pbDbg + 4, pe32->e32_debuglen - 4);
|
|---|
| 136 |
|
|---|
| 137 | default:
|
|---|
| 138 | printf("Invalid debug type, %c (%d)\n", pbDbg[3], pbDbg[3]);
|
|---|
| 139 | return ERROR_INVALID_DATA;
|
|---|
| 140 | }
|
|---|
| 141 |
|
|---|
| 142 | /*
|
|---|
| 143 | * Dump debug data
|
|---|
| 144 | */
|
|---|
| 145 | printf("\ndumps debug data\n");
|
|---|
| 146 | dumpHex(stdout, pbDbg + 4, pe32->e32_debuglen - 4);
|
|---|
| 147 | }
|
|---|
| 148 | else
|
|---|
| 149 | {
|
|---|
| 150 | printf("Invalid debug signature\n");
|
|---|
| 151 | return ERROR_INVALID_DATA;
|
|---|
| 152 | }
|
|---|
| 153 | }
|
|---|
| 154 | else
|
|---|
| 155 | printf(" - no debug info -\n");
|
|---|
| 156 |
|
|---|
| 157 | return NO_ERROR;
|
|---|
| 158 | }
|
|---|
| 159 |
|
|---|
| 160 |
|
|---|
| 161 | /**
|
|---|
| 162 | * Dumps binary data to file handle.
|
|---|
| 163 | * @param phOut Output file handle.
|
|---|
| 164 | * @param pb Pointer to debug data.
|
|---|
| 165 | * @param cb Size of debug data.
|
|---|
| 166 | *
|
|---|
| 167 | * HLL:
|
|---|
| 168 | * Starts with a 4 byte word with the offset (from start of HLL data) to
|
|---|
| 169 | * the number of entries. (what entries is yet to come)
|
|---|
| 170 | *
|
|---|
| 171 | *
|
|---|
| 172 | */
|
|---|
| 173 | static int dumpHLL(FILE *phOut, PBYTE pb, int cb)
|
|---|
| 174 | {
|
|---|
| 175 | PHLLDIR pDir;
|
|---|
| 176 | ULONG offDir;
|
|---|
| 177 | int i;
|
|---|
| 178 |
|
|---|
| 179 | /*
|
|---|
| 180 | * Get number of entries.
|
|---|
| 181 | */
|
|---|
| 182 | offDir = *(PULONG)pb;
|
|---|
| 183 | if (offDir + 4 >= cb)
|
|---|
| 184 | {
|
|---|
| 185 | fprintf(phOut, "error: offcEntries is incorrect!\n");
|
|---|
| 186 | return ERROR_INVALID_DATA;
|
|---|
| 187 | }
|
|---|
| 188 | pDir = (PHLLDIR)(pb + offDir);
|
|---|
| 189 | fprintf(phOut, "Directory offset=0x%08x cEntries=%d(0x%x)\n",
|
|---|
| 190 | offDir, pDir->cEntries, pDir->cEntries);
|
|---|
| 191 |
|
|---|
| 192 |
|
|---|
| 193 | /*
|
|---|
| 194 | * Directory sanity check.
|
|---|
| 195 | */
|
|---|
| 196 | if ((PBYTE)&pDir->aEntries[pDir->cEntries] - pb >= cb)
|
|---|
| 197 | {
|
|---|
| 198 | fprintf(phOut, "Error: Directory is to big!\n");
|
|---|
| 199 | return ERROR_INVALID_DATA;
|
|---|
| 200 | }
|
|---|
| 201 |
|
|---|
| 202 |
|
|---|
| 203 |
|
|---|
| 204 | /*
|
|---|
| 205 | * Loop thru the directory.
|
|---|
| 206 | */
|
|---|
| 207 | for (i = 0; i < pDir->cEntries; i++)
|
|---|
| 208 | {
|
|---|
| 209 | fprintf(phOut, "Directory Entry %d (0x%x):\n", i, i);
|
|---|
| 210 | fprintf(phOut, " usType 0x%08x (%d)\n"
|
|---|
| 211 | " iMod 0x%08x (%d)\n"
|
|---|
| 212 | " off 0x%08x (%d)\n"
|
|---|
| 213 | " cb 0x%08x (%d)\n",
|
|---|
| 214 | pDir->aEntries[i].usType,
|
|---|
| 215 | pDir->aEntries[i].usType,
|
|---|
| 216 | pDir->aEntries[i].iMod,
|
|---|
| 217 | pDir->aEntries[i].iMod,
|
|---|
| 218 | pDir->aEntries[i].off,
|
|---|
| 219 | pDir->aEntries[i].off,
|
|---|
| 220 | pDir->aEntries[i].cb,
|
|---|
| 221 | pDir->aEntries[i].cb
|
|---|
| 222 | );
|
|---|
| 223 |
|
|---|
| 224 | switch (pDir->aEntries[i].usType)
|
|---|
| 225 | {
|
|---|
| 226 | case HLL_DE_MODULES: /* Filename */
|
|---|
| 227 | printf(" Modulename: %*.s\n",
|
|---|
| 228 | pDir->aEntries[i].cb,
|
|---|
| 229 | pDir->aEntries[i].off + pb);
|
|---|
| 230 | dumpHex(phOut, pDir->aEntries[i].off + pb, pDir->aEntries[i].cb);
|
|---|
| 231 | break;
|
|---|
| 232 |
|
|---|
| 233 | case HLL_DE_PUBLICS: /* Public symbols */
|
|---|
| 234 | break;
|
|---|
| 235 |
|
|---|
| 236 | case HLL_DE_TYPES: /* Types */
|
|---|
| 237 | break;
|
|---|
| 238 |
|
|---|
| 239 | case HLL_DE_SYMBOLS: /* Symbols */
|
|---|
| 240 | break;
|
|---|
| 241 |
|
|---|
| 242 | case HLL_DE_LIBRARIES: /* Libraries */
|
|---|
| 243 | break;
|
|---|
| 244 |
|
|---|
| 245 | case HLL_DE_SRCLINES: /* Line numbers - (IBM C/2 1.1) */
|
|---|
| 246 | break;
|
|---|
| 247 |
|
|---|
| 248 | case HLL_DE_SRCLNSEG: /* Line numbers - (MSC 6.00) */
|
|---|
| 249 | break;
|
|---|
| 250 |
|
|---|
| 251 | case HLL_DE_IBMSRC: /* Line numbers - (IBM HLL) */
|
|---|
| 252 | break;
|
|---|
| 253 |
|
|---|
| 254 | default:
|
|---|
| 255 | fprintf(phOut, " Error - unknown entry type. (%x)\n", pDir->aEntries[i].usType);
|
|---|
| 256 | }
|
|---|
| 257 |
|
|---|
| 258 | }
|
|---|
| 259 |
|
|---|
| 260 |
|
|---|
| 261 | /* - temporary - */
|
|---|
| 262 | printf("\ndumps debug data\n");
|
|---|
| 263 | dumpHex(stdout, pb, cb);
|
|---|
| 264 |
|
|---|
| 265 | return NO_ERROR;
|
|---|
| 266 | }
|
|---|
| 267 |
|
|---|
| 268 |
|
|---|
| 269 |
|
|---|
| 270 | /**
|
|---|
| 271 | * Dumps binary data to file handle.
|
|---|
| 272 | * @param phOut Output file handle.
|
|---|
| 273 | * @param pb Pointer to data.
|
|---|
| 274 | * @param cb Count of bytes to dump.
|
|---|
| 275 | */
|
|---|
| 276 | static void dumpHex(FILE *phOut, PBYTE pb, int cb)
|
|---|
| 277 | {
|
|---|
| 278 | int i;
|
|---|
| 279 |
|
|---|
| 280 | for (i = 0; i < cb; i += 16)
|
|---|
| 281 | {
|
|---|
| 282 | int j;
|
|---|
| 283 | /* write offset */
|
|---|
| 284 | fprintf(phOut, "%08x ", i);
|
|---|
| 285 |
|
|---|
| 286 | /* write data (hex value) */
|
|---|
| 287 | for (j = 0; j < 16; j++)
|
|---|
| 288 | {
|
|---|
| 289 | int f = i + j < cb;
|
|---|
| 290 | unsigned char uch = f ? pb[i + j] : 0;
|
|---|
| 291 | if (j == 3 || j == 11)
|
|---|
| 292 | fprintf(phOut, f ? "%02x-" : " -", uch);
|
|---|
| 293 | else if (j == 7)
|
|---|
| 294 | fprintf(phOut, f ? "%02x - " : " - ", uch);
|
|---|
| 295 | else
|
|---|
| 296 | fprintf(phOut, f ? "%02x " : " ", uch);
|
|---|
| 297 | }
|
|---|
| 298 | fprintf(phOut, " ");
|
|---|
| 299 |
|
|---|
| 300 | /* write ASCII */
|
|---|
| 301 | for (j = 0; j < 16; j++)
|
|---|
| 302 | {
|
|---|
| 303 | if (i + j < cb)
|
|---|
| 304 | {
|
|---|
| 305 | if (isprint(pb[i + j]))
|
|---|
| 306 | fprintf(phOut, "%c", pb[i + j]);
|
|---|
| 307 | else
|
|---|
| 308 | fprintf(phOut, ".");
|
|---|
| 309 | }
|
|---|
| 310 | else
|
|---|
| 311 | fprintf(phOut, " ");
|
|---|
| 312 | }
|
|---|
| 313 | fprintf(phOut, "\n");
|
|---|
| 314 | }
|
|---|
| 315 | }
|
|---|
| 316 |
|
|---|
| 317 |
|
|---|
| 318 |
|
|---|
| 319 | /**
|
|---|
| 320 | * Creates a memory buffer for a binary file.
|
|---|
| 321 | * @returns Pointer to file memoryblock. NULL on error.
|
|---|
| 322 | * @param pszFilename Pointer to filename string.
|
|---|
| 323 | * @remark This function is the one using most of the execution
|
|---|
| 324 | * time (DosRead + DosOpen) - about 70% of the execution time!
|
|---|
| 325 | */
|
|---|
| 326 | static void *readfile(const char *pszFilename)
|
|---|
| 327 | {
|
|---|
| 328 | void *pvFile = NULL;
|
|---|
| 329 | FILE *phFile;
|
|---|
| 330 |
|
|---|
| 331 | phFile = fopen(pszFilename, "rb");
|
|---|
| 332 | if (phFile != NULL)
|
|---|
| 333 | {
|
|---|
| 334 | signed long cbFile = fsize(phFile);
|
|---|
| 335 | if (cbFile > 0)
|
|---|
| 336 | {
|
|---|
| 337 | pvFile = malloc(cbFile + 1);
|
|---|
| 338 | if (pvFile != NULL)
|
|---|
| 339 | {
|
|---|
| 340 | memset(pvFile, 0, cbFile + 1);
|
|---|
| 341 | if (fread(pvFile, 1, cbFile, phFile) == 0)
|
|---|
| 342 | { /* failed! */
|
|---|
| 343 | free(pvFile);
|
|---|
| 344 | pvFile = NULL;
|
|---|
| 345 | }
|
|---|
| 346 | }
|
|---|
| 347 | else
|
|---|
| 348 | fprintf(stderr, "warning/error: failed to open file %s\n", pszFilename);
|
|---|
| 349 | }
|
|---|
| 350 | fclose(phFile);
|
|---|
| 351 | }
|
|---|
| 352 | return pvFile;
|
|---|
| 353 | }
|
|---|
| 354 |
|
|---|
| 355 |
|
|---|
| 356 |
|
|---|
| 357 | /**
|
|---|
| 358 | * Find the size of a file.
|
|---|
| 359 | * @returns Size of file. -1 on error.
|
|---|
| 360 | * @param phFile File handle.
|
|---|
| 361 | */
|
|---|
| 362 | static signed long fsize(FILE *phFile)
|
|---|
| 363 | {
|
|---|
| 364 | int ipos;
|
|---|
| 365 | signed long cb;
|
|---|
| 366 |
|
|---|
| 367 | if ((ipos = ftell(phFile)) < 0
|
|---|
| 368 | ||
|
|---|
| 369 | fseek(phFile, 0, SEEK_END) != 0
|
|---|
| 370 | ||
|
|---|
| 371 | (cb = ftell(phFile)) < 0
|
|---|
| 372 | ||
|
|---|
| 373 | fseek(phFile, ipos, SEEK_SET) != 0
|
|---|
| 374 | )
|
|---|
| 375 | cb = -1;
|
|---|
| 376 | return cb;
|
|---|
| 377 | }
|
|---|
| 378 |
|
|---|