source: trunk/src/win32k/elf2lx/elfdumper.cpp@ 2497

Last change on this file since 2497 was 2497, checked in by bird, 26 years ago

Pre-Initial backup commit.

File size: 21.4 KB
Line 
1/* $Id: elfdumper.cpp,v 1.1 2000-01-22 00:49:21 bird Exp $
2 *
3 * ELF dumper utility
4 *
5 * Copyright (c) 1999 knut st. osmundsen
6 *
7 * Project Odin Software License can be found in LICENSE.TXT
8 *
9 */
10
11/*******************************************************************************
12* Defined Constants And Macros *
13*******************************************************************************/
14#define TRUE 1
15#define FALSE 0
16
17#define PRINTCASE(Level,Value) \
18 case Value: printData(Level, #Value); break
19
20#define PRINTFLAG(Flags,Flag) \
21 if (((Flags) & (Flag)) == (Flag)) \
22 printData(#Flag " ")
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <stdarg.h>
31#include <assert.h>
32
33#include "elf.h"
34
35/*******************************************************************************
36* Structures and Typedefs *
37*******************************************************************************/
38typedef unsigned long BOOL;
39typedef struct
40{
41 BOOL fdummy;
42} OPTIONS, *POPTIONS;
43
44/*******************************************************************************
45* Global Variables *
46*******************************************************************************/
47BOOL fPrintLongData = FALSE;
48BOOL fPrintLongDataIndented = FALSE;
49int iPrintLongDataIndentLevel = -1;
50
51/*******************************************************************************
52* Internal Functions *
53*******************************************************************************/
54static BOOL read(FILE *phFile, void *pv, unsigned long cb, unsigned long off);
55static void syntax(void);
56void * loadELFImage(FILE *phFile);
57int dumpELFImage(void *pv);
58int dumpELFHdr(Elf32_Ehdr *pHdr32);
59int dumpELFSectionHeader(Elf32_Ehdr * pHdr32, int iShdr);
60int dumpELFSectionHeaderTable(Elf32_Ehdr * pHdr32);
61char * getELFSectionNameStringTable(Elf32_Ehdr * pHdr32);
62int dumpELFSymbolTable(Elf32_Ehdr * pHdr32, Elf32_Shdr * pShdr);
63int dumpELFRelcations(Elf32_Ehdr * pHdr32, Elf32_Shdr * pShdr);
64int dumpELFRelcationsA(Elf32_Ehdr * pHdr32, Elf32_Shdr * pShdr);
65
66/* output helpers */
67void printHeader(char *pszHeader);
68void print(int iIndentLevel, char *pszName, char *pszDataFormat, ...);
69void print(int iIndentLevel, char *pszText);
70void printBeginLongData(int iIndentLevel);
71void printEndLongData(void);
72void printData(char *pszDataFormat, ...);
73void printData(int iIndentLevel, char *pszDataFormat, ...);
74int printGetIndentData(int iIndentLevel);
75int printGetIndent(int iIndentLevel);
76void printerr(const char *pszMsg, ...);
77
78
79/**
80 * Main function.
81 * @returns Number of signals.
82 * @param argc Argument count.
83 * @param argv Argument array.
84 */
85int main(int argc, char **argv)
86{
87 OPTIONS options = {TRUE};
88 BOOL fFatal = FALSE;
89 int iRc = 0;
90 int argi;
91
92 /**************************************************************************
93 * parse arguments.
94 * options: -h or -? Syntax help.
95 **************************************************************************/
96 argi = 1;
97 while (argi < argc && !fFatal)
98 {
99 if(argv[argi][0] == '-' || argv[argi][0] == '/')
100 {
101 switch (argv[argi][1])
102 {
103 case 'h':
104 case 'H':
105 case '?':
106 syntax();
107 return 0;
108
109 default:
110 printerr("incorrect parameter. (argi=%d, argv[argi]=%s)", argi, argv[argi]);
111 fFatal = TRUE;
112 break;
113 }
114 }
115 else
116 {
117 FILE *phFile;
118
119 phFile = fopen(argv[argi], "rb");
120 if (phFile != NULL)
121 {
122 void *pv = loadELFImage(phFile);
123 if (pv != NULL)
124 {
125 dumpELFImage(pv);
126 free(pv);
127 }
128 fclose(phFile);
129 }
130 else
131 {
132 printerr("failed to open file '%s'.", argv[argi]);
133 iRc++;
134 }
135 }
136 argi++;
137 }
138 return iRc;
139}
140
141
142static void syntax(void)
143{
144 printf("\n"
145 "ELFDumper v0.0.0 - \"Not Implemented\"\n"
146 "------------------------------------\n"
147 "syntax: ELFDumper.exe [-?] <files to dump>\n"
148 );
149}
150
151
152/**
153 * Loads an ELF image into memory for dumping.
154 * @returns Pointer to ELF image.
155 * @param phFile File handle to the ELF image file.
156 * @author knut st. osmundsen
157 */
158void * loadELFImage(FILE *phFile)
159{
160 size_t cbFile;
161
162 fseek(phFile, 0, SEEK_END);
163 cbFile = (size_t)ftell(phFile);
164
165 if (cbFile > sizeof(Elf32_Ehdr))
166 {
167 void *pv = malloc(cbFile);
168 if (pv != NULL)
169 {
170 if (read(phFile, pv, cbFile, 0))
171 {
172 return pv;
173 }
174 else
175 printerr("failed to read file.");
176 free(pv);
177 }
178 else
179 printerr("failed to allocate memory!. (%d bytes)", cbFile);
180 }
181 else
182 printerr("file is less than the size of the elf header! (%d)", cbFile);
183 return NULL;
184}
185
186
187/**
188 * Dumps the loaded ELF image.
189 * @returns Error code. (0 is success)
190 * @param pv Pointer to the base of the ...
191 * @author knut st. osmundsen
192 */
193int dumpELFImage(void *pv)
194{
195 Elf32_Ehdr *pHdr32 = (Elf32_Ehdr *)pv;
196 int rc = 0;
197
198 if (*(unsigned long *)pv == ELFMAGICLSB)
199 {
200 rc = dumpELFHdr(pHdr32);
201 if (rc == 0)
202 rc = dumpELFSectionHeaderTable(pHdr32);
203 }
204 else
205 {
206 printerr("no ELF signature was found");
207 rc = -1;
208 }
209 return rc;
210}
211
212
213/**
214 * Dumps the ELF header.
215 * @returns 0 on success, errorcode on error (-1).
216 * @param pHdr32 Pointer to the ELF32 header to dump.
217 * @author knut st. osmundsen
218 */
219int dumpELFHdr(Elf32_Ehdr *pHdr32)
220{
221 int i;
222 int iRc = 0;
223 printHeader("ELF Header");
224 printBeginLongData(0);
225 print(0, "e_ident");
226
227 for (i = 0; i < EI_INDENT; i++)
228 printData(i > 0 && i <= 3 ? "%c " : "%02x ", pHdr32->e_ident[i]);
229 printEndLongData();
230
231 for (i = 0; i < EI_INDENT; i++)
232 {
233 switch (i)
234 {
235 case EI_CLASS:
236 switch (pHdr32->e_ident[i])
237 {
238 PRINTCASE(0,ELFCLASS32);
239 case ELFCLASS64:
240 printData(0, "ELFCLASS64");
241 printerr("class not supported");
242 iRc = -1;
243 break;
244 case ELFCLASSNUM:
245 printData(0, "ELFCLASSNUM");
246 printerr("class not supported");
247 iRc = -1;
248 break;
249
250 default:
251 printData(0, "Invalid class 0x%02x", pHdr32->e_ident[i]);
252 printerr("class not supported");
253 iRc = -1;
254 }
255 break;
256 case EI_DATA:
257 switch (pHdr32->e_ident[i])
258 {
259 PRINTCASE(0,ELFDATA2LSB);
260 case ELFDATA2MSB:
261 printData(0, "ELFDATA2MSB");
262 printerr("Data encoding not supported");
263 iRc = -1;
264 break;
265 default:
266 printData(0, "Invalid data encoding 0x%02x", pHdr32->e_ident[i]);
267 printerr("Data encoding not supported");
268 iRc = -1;
269 }
270 break;
271 case EI_VERSION:
272 switch (pHdr32->e_ident[i])
273 {
274 PRINTCASE(0,EV_CURRENT);
275 PRINTCASE(0,EV_NUM);
276 default:
277 printData(0, "Unknown ELF version 0x%02x", pHdr32->e_ident[i]);
278 iRc = -1;
279 }
280 break;
281 }
282 }
283
284 if (iRc == 0)
285 {
286 print(0, "e_type", "0x%04x", pHdr32->e_type);
287 switch (pHdr32->e_type)
288 {
289 PRINTCASE(1,ET_NONE);
290 PRINTCASE(1,ET_REL);
291 PRINTCASE(1,ET_EXEC);
292 PRINTCASE(1,ET_DYN);
293 PRINTCASE(1,ET_CORE);
294 //default:
295 }
296 print(0, "e_machine", "0x%04x", pHdr32->e_machine);
297 switch (pHdr32->e_machine)
298 {
299 PRINTCASE(1,EM_NONE);
300 PRINTCASE(1,EM_M32);
301 PRINTCASE(1,EM_SPARC);
302 PRINTCASE(1,EM_386);
303 PRINTCASE(1,EM_68K);
304 PRINTCASE(1,EM_88K);
305 PRINTCASE(1,EM_486);
306 PRINTCASE(1,EM_860);
307 PRINTCASE(1,EM_MIPS);
308 PRINTCASE(1,EM_MIPS_RS4_BE);
309 PRINTCASE(1,EM_SPARC64);
310 PRINTCASE(1,EM_PARISC);
311 PRINTCASE(1,EM_SPARC32PLUS);
312 PRINTCASE(1,EM_PPC);
313 PRINTCASE(1,EM_ALPHA);
314 //default:
315 }
316 print(0, "e_version", "%d (%s)", pHdr32->e_version,
317 pHdr32->e_version == EV_CURRENT ? "EV_CURRENT"
318 : pHdr32->e_version == EV_NUM ? "EV_NUM" : "unknown/invalid");
319 print(0, "e_entry", "0x%08x", pHdr32->e_entry);
320 print(0, "e_phoff", "0x%08x", pHdr32->e_phoff);
321 print(0, "e_shoff", "0x%08x", pHdr32->e_shoff);
322 print(0, "e_flags", "0x%08x", pHdr32->e_flags);
323 print(0, "e_ehsize", "%d (Current=%d)", pHdr32->e_ehsize, sizeof(Elf32_Ehdr));
324 print(0, "e_phentsize", "%d (Current=%d)", pHdr32->e_phentsize, -1/* sizeof(Elf32_Phdr)*/);
325 print(0, "e_phnum", "0x%04x", pHdr32->e_phnum);
326 print(0, "e_shentsize", "%d (Current=%d)", pHdr32->e_shentsize, sizeof(Elf32_Shdr));
327 print(0, "e_shnum", "0x%04x", pHdr32->e_shnum);
328 print(0, "e_shstrndx", "0x%04x", pHdr32->e_shstrndx);
329 }
330
331 return iRc;
332}
333
334
335
336/**
337 * Dumps the section header table of an ELF image.
338 * @returns 0 on success. Errorcode on error (-1).
339 * @param pHdr32 Pointer to the image.
340 * @author knut st. osmundsen
341 */
342int dumpELFSectionHeaderTable(Elf32_Ehdr * pHdr32)
343{
344 int i;
345 int rc = 0;
346
347 printHeader("Section Header Table");
348
349 for (i = 0; i < pHdr32->e_shnum && rc == 0; i++)
350 {
351 if (i > 0)
352 print(0,"");
353 rc = dumpELFSectionHeader(pHdr32, i);
354 }
355 return rc;
356}
357
358
359/**
360 * Dumps the section header table of an ELF image.
361 * @returns 0 on success. Errorcode on error (-1).
362 * @param pHdr32 Pointer to the image.
363 * @param iShdr Section number.
364 * @author knut st. osmundsen
365 */
366int dumpELFSectionHeader(Elf32_Ehdr * pHdr32, int iShdr)
367{
368 Elf32_Shdr * pShdr = (Elf32_Shdr*)((unsigned)pHdr32 + pHdr32->e_shoff + pHdr32->e_shentsize*iShdr);
369 char * paszStrings = getELFSectionNameStringTable(pHdr32);
370 print(0, "Section Header", "no. %d offset 0x%08x", iShdr, (unsigned)pShdr - (unsigned)pHdr32);
371 if (paszStrings != NULL && pShdr->sh_name != 0)
372 print(1, "sh_name", "%s (0x%01x)", paszStrings + pShdr->sh_name, pShdr->sh_name);
373 else
374 print(1, "sh_name", "0x%08x", pShdr->sh_name);
375 print(1, "sh_type", "0x%08x", pShdr->sh_type);
376 switch (pShdr->sh_type)
377 {
378 PRINTCASE(1,SHT_NULL);
379 PRINTCASE(1,SHT_PROGBITS);
380 PRINTCASE(1,SHT_SYMTAB);
381 PRINTCASE(1,SHT_STRTAB);
382 PRINTCASE(1,SHT_RELA);
383 PRINTCASE(1,SHT_HASH);
384 PRINTCASE(1,SHT_DYNAMIC);
385 PRINTCASE(1,SHT_NOTE);
386 PRINTCASE(1,SHT_NOBITS);
387 PRINTCASE(1,SHT_REL);
388 PRINTCASE(1,SHT_SHLIB);
389 PRINTCASE(1,SHT_DYNSYM);
390 PRINTCASE(1,SHT_NUM);
391 default:
392 if (pShdr->sh_type >= SHT_LOPROC && pShdr->sh_type >= SHT_HIPROC)
393 printData(1, "Processor-specific");
394 else if (pShdr->sh_type >= SHT_LOUSER && pShdr->sh_type <= SHT_HIUSER)
395 printData(1, "Application program specific");
396 else
397 printData(1, "unknown");
398 }
399 print(1, "sh_flags", "0x%08x", pShdr->sh_flags);
400 printBeginLongData(1);
401 PRINTFLAG(pShdr->sh_flags,SHF_WRITE);
402 PRINTFLAG(pShdr->sh_flags,SHF_ALLOC);
403 PRINTFLAG(pShdr->sh_flags,SHF_EXECINSTR);
404 if (pShdr->sh_flags & SHF_MASKPROC)
405 printData("SHF_MASKPROC");
406 printEndLongData();
407 print(1, "sh_addr", "0x%08x", pShdr->sh_addr);
408 print(1, "sh_offset", "0x%08x", pShdr->sh_offset);
409 print(1, "sh_size", "0x%08x", pShdr->sh_size);
410 print(1, "sh_link", "0x%08x", pShdr->sh_link);
411 print(1, "sh_info", "0x%08x", pShdr->sh_info);
412 print(1, "sh_addralign", "0x%08x", pShdr->sh_addralign);
413 print(1, "sh_entsize", "0x%08x", pShdr->sh_entsize);
414
415 /* process evt. known contents. */
416 switch (pShdr->sh_type)
417 {
418 case SHT_SYMTAB:
419 case SHT_DYNSYM:
420 dumpELFSymbolTable(pHdr32, pShdr);
421 break;
422 case SHT_REL:
423 dumpELFRelcations(pHdr32, pShdr);
424 break;
425 case SHT_RELA:
426 break;
427 case SHT_HASH:
428 break;
429 case SHT_NOTE:
430 break;
431 }
432
433 return 0;
434}
435
436
437/**
438 * Gets the Section Name String Table.
439 * @returns Pointer to the string table.
440 * @param pHdr32 Pointer to the image.
441 * @author knut st. osmundsen
442 */
443char *getELFSectionNameStringTable(Elf32_Ehdr * pHdr32)
444{
445 if (pHdr32->e_shstrndx != SHN_UNDEF)
446 {
447 Elf32_Shdr * pShdr = (Elf32_Shdr*)((unsigned)pHdr32 + pHdr32->e_shoff + pHdr32->e_shentsize * pHdr32->e_shstrndx);
448 return (char*)((unsigned)pHdr32 + pShdr->sh_offset);
449 }
450 return NULL;
451}
452
453
454/**
455 * Dumps a symboltable.
456 * @returns 0 on success. Errorcode on error.
457 * @param pHdr32 Pointer to the image.
458 * @param pShdr Pointer to the section containing the symboltable.
459 * @author knut st. osmundsen
460 */
461int dumpELFSymbolTable(Elf32_Ehdr * pHdr32, Elf32_Shdr * pShdr)
462{
463 Elf32_Shdr * pShdrStr = (Elf32_Shdr*)((unsigned)pHdr32 + pHdr32->e_shoff + pHdr32->e_shentsize*pShdr->sh_link);
464 Elf32_Sym * pSym = (Elf32_Sym*)((unsigned)pHdr32 + pShdr->sh_offset);
465 unsigned off = 0;
466 char * paszStrings = (char *)((unsigned)pHdr32 + pShdrStr->sh_offset);
467
468 /* Fixme?: sh_info - One greater than the symbol table index of the last local symbol (binding STB_LOCAL). */
469
470 print(2, "Symbol table:");
471 while (off < pShdr->sh_size)
472 {
473 flushall();
474 print(2, "st_name", "%s", paszStrings + pSym->st_name);
475 print(3, "st_value", "0x%08x", pSym->st_value);
476 print(3, "st_size", "%d", pSym->st_size);
477 printBeginLongData(3);
478 print(3, "st_info", "0x%02x", pSym->st_info);
479 printData(" ");
480 switch (ELF32_ST_BIND(pSym->st_info))
481 {
482 PRINTCASE(3,STB_LOCAL);
483 PRINTCASE(3,STB_GLOBAL);
484 PRINTCASE(3,STB_WEAK);
485 default:
486 printData("unknown binding");
487 }
488 printData(" ");
489 switch (ELF32_ST_TYPE(pSym->st_info))
490 {
491 PRINTCASE(3,STT_NOTYPE);
492 PRINTCASE(3,STT_OBJECT);
493 PRINTCASE(3,STT_FUNC);
494 PRINTCASE(3,STT_SECTION);
495 PRINTCASE(3,STT_FILE);
496 default:
497 printData("unknown type");
498 }
499 printEndLongData();
500 print(3, "st_other", "0x%02x", pSym->st_other);
501 print(3, "st_shndx", "0x%04x", pSym->st_shndx);
502
503 /* next */
504 pSym = (Elf32_Sym*)((unsigned)pSym + pShdr->sh_entsize);
505 off += pShdr->sh_entsize;
506 }
507 return 0;
508}
509
510
511int dumpELFRelcations(Elf32_Ehdr * pHdr32, Elf32_Shdr * pShdr)
512{
513 Elf32_Rel * pRel = (Elf32_Rel*)((unsigned)pHdr32 + pShdr->sh_offset);
514 unsigned off = 0;
515
516 while (off < pShdr->sh_size)
517 {
518 printBeginLongData(2);
519 print(2, "Relocation", "off=0x%08x type=", pRel->r_offset);
520 switch (ELF32_R_TYPE(pRel->r_info))
521 {
522 PRINTCASE(2,R_386_NONE);
523 PRINTCASE(2,R_386_32);
524 PRINTCASE(2,R_386_PC32);
525 PRINTCASE(2,R_386_GOT32);
526 PRINTCASE(2,R_386_PLT32);
527 PRINTCASE(2,R_386_COPY);
528 PRINTCASE(2,R_386_GLOB_DAT);
529 PRINTCASE(2,R_386_JMP_SLOT);
530 PRINTCASE(2,R_386_RELATIVE);
531 PRINTCASE(2,R_386_GOT_OFF);
532 PRINTCASE(2,R_386_GOTPC);
533 default:
534 printData("<unknown type>");
535 }
536 if (ELF32_R_SYM(pRel->r_info) != STN_UNDEF)
537 printData(" sym=STN_UNDEF");
538 else
539 printData(" sym=0x%08x", ELF32_R_SYM(pRel->r_info));
540 printEndLongData();
541
542 /* next */
543 pRel = (Elf32_Rel*)((unsigned)pRel + pShdr->sh_entsize);
544 off += pShdr->sh_entsize;
545 }
546 return 0;
547}
548
549int dumpELFRelcationsA(Elf32_Ehdr * pHdr32, Elf32_Shdr * pShdr)
550{
551 Elf32_Rela * pRela = (Elf32_Rela*)((unsigned)pHdr32 + pShdr->sh_offset);
552 unsigned off = 0;
553
554 while (off < pShdr->sh_size)
555 {
556 printBeginLongData(2);
557 print(2, "Relocation+Addend", "off=0x%08x type=", pRela->r_offset);
558 switch (ELF32_R_TYPE(pRela->r_info))
559 {
560 PRINTCASE(2,R_386_NONE);
561 PRINTCASE(2,R_386_32);
562 PRINTCASE(2,R_386_PC32);
563 PRINTCASE(2,R_386_GOT32);
564 PRINTCASE(2,R_386_PLT32);
565 PRINTCASE(2,R_386_COPY);
566 PRINTCASE(2,R_386_GLOB_DAT);
567 PRINTCASE(2,R_386_JMP_SLOT);
568 PRINTCASE(2,R_386_RELATIVE);
569 PRINTCASE(2,R_386_GOT_OFF);
570 PRINTCASE(2,R_386_GOTPC);
571 default:
572 printData("<unknown type>");
573 }
574 if (ELF32_R_SYM(pRela->r_info) != STN_UNDEF)
575 printData(" sym=STN_UNDEF");
576 else
577 printData(" sym=0x%08x", ELF32_R_SYM(pRela->r_info));
578 printData(" add=0x%08x", pRela->r_addend);
579 printEndLongData();
580
581 /* next */
582 pRela = (Elf32_Rela*)((unsigned)pRela + pShdr->sh_entsize);
583 off += pShdr->sh_entsize;
584 }
585 return 0;
586}
587
588
589
590
591
592/*
593 * Helper functions
594 */
595
596/**
597 * Reads for the given file at a specific offset.
598 * @returns Success indicator (TRUE/FALSE).
599 * @param phFile File handle.
600 * @param pv Pointer to output buffer.
601 * @param cb The count of bytes to read.
602 * @param off Offset (from the begining of the file) to start reading from.
603 * @status completely implemented.
604 * @author knut st. osmundsen
605 */
606static BOOL read(FILE *phFile, void *pv, unsigned long cb, unsigned long off)
607{
608 if (fseek(phFile, off, SEEK_SET) == 0)
609 {
610 if (fread(pv, (size_t)cb, 1, phFile) == 1)
611 return 1;
612 else
613 return 0;
614 }
615 else
616 return 0;
617}
618
619void printHeader(char *pszHeader)
620{
621 static BOOL fFirst = TRUE;
622 if (!fFirst)
623 putchar('\n');
624 else
625 fFirst = FALSE;
626
627 int i = strlen(pszHeader);
628 puts(pszHeader);
629 for (i=i; i >= 0; i--)
630 putchar('-');
631 putchar('\n');
632}
633
634
635void print(int iIndentLevel, char *pszName, char *pszDataFormat, ...)
636{
637 va_list arg;
638 int i = printf("%*s%s", printGetIndent(iIndentLevel), "", pszName);
639 i = printGetIndentData(iIndentLevel) - i;
640 for (i = i > 0 ? i : 1; i > 0; i--)
641 putchar(' ');
642 va_start(arg, pszDataFormat);
643 vprintf(pszDataFormat, arg);
644 va_end(arg);
645
646 if (!fPrintLongData)
647 {
648 putchar('\n');
649 fPrintLongDataIndented = FALSE;
650 }
651 else
652 fPrintLongDataIndented = TRUE;
653}
654
655void print(int iIndentLevel, char *pszText)
656{
657 int i = printf("%*s%s", printGetIndent(iIndentLevel), "", pszText);
658 if (!fPrintLongData)
659 {
660 putchar('\n');
661 fPrintLongDataIndented = FALSE;
662 }
663 else
664 {
665 i = printGetIndentData(iIndentLevel) - i;
666 printf("%*s", i > 0 ? i : 1, "");
667 fPrintLongDataIndented = TRUE;
668 }
669}
670
671void printBeginLongData(int iIndentLevel)
672{
673 assert(!fPrintLongData);
674 fPrintLongData = TRUE;
675 iPrintLongDataIndentLevel = iIndentLevel;
676 fPrintLongDataIndented = FALSE;
677}
678
679void printEndLongData(void)
680{
681 assert(fPrintLongData == TRUE);
682 fPrintLongData = FALSE;
683 putchar('\n');
684}
685
686void printData(char *pszDataFormat, ...)
687{
688 va_list arg;
689
690 if (!fPrintLongDataIndented)
691 {
692 printf("%*s", printGetIndentData(iPrintLongDataIndentLevel), "");
693 fPrintLongDataIndented = TRUE;
694 }
695
696 va_start(arg, pszDataFormat);
697 vprintf(pszDataFormat, arg);
698 va_end(arg);
699}
700
701
702void printData(int iIndentLevel, char *pszDataFormat, ...)
703{
704 va_list arg;
705
706 if (!fPrintLongDataIndented)
707 {
708 printf("%*s", printGetIndentData(iIndentLevel), "");
709 fPrintLongDataIndented = TRUE;
710 }
711
712 va_start(arg, pszDataFormat);
713 vprintf(pszDataFormat, arg);
714 va_end(arg);
715
716 if (!fPrintLongData)
717 putchar('\n');
718}
719
720int printGetIndentData(int iIndentLevel)
721{
722 static int idata[4] = {23, 27, 30, 33};
723 assert(iIndentLevel < 4);
724 return idata[iIndentLevel];
725}
726
727int printGetIndent(int iIndentLevel)
728{
729 static int idata[4] = {3, 6, 9, 12};
730 assert(iIndentLevel < 4);
731 return idata[iIndentLevel];
732}
733
734void printerr(const char *pszMsg, ...)
735{
736 va_list arg;
737
738 printf("error: ");
739
740 va_start(arg, pszMsg);
741 vprintf(pszMsg, arg);
742 va_end(arg);
743
744 putchar('\n');
745}
746
Note: See TracBrowser for help on using the repository browser.