/* out.c: Top-level (and bitness-neutral) output functions. * Copyright (C) 1999,2011 by Brian Raiter * License GPLv2+: GNU GPL version 2 or later. * This is free software; you are free to change and redistribute it. * There is NO WARRANTY, to the extent permitted by law. */ #include #include #include "gen.h" #include "readelf.h" #include "pieces.h" #include "address.h" #include "shdrtab.h" #include "outbase.h" #include "outitems.h" #include "outelf64.h" #include "outelf32.h" #include "out.h" static int forcehex = FALSE; /* make outbytes() output hex array */ /* Forces outbytes() to always output an array of hexadecimal values. */ void forcehexbytes(void) { forcehex = TRUE; } /* The output function for a piece not actually present in the ELF * file image. */ static void outnothing(void const *ptr, long size, int ndx) { (void)ptr; (void)size; (void)ndx; out("{ }"); } /* The output function for pieces of type P_UNCLAIMED, P_SECTION, * P_BYTES, or P_STRINGS. The contents are output either as a literal * string, an array of character values, or an array of hexadecimal * byte values. The last will be used if the contents contain an * excess of non-graphic, non-ASCII characters, or if the forcehex * flag is set. Otherwise one of the first two representations will * be selected based on whether or not the contents appear to be * NUL-terminated. */ static void outbytes(void const *ptr, long size, int ndx) { unsigned char const *bytes = ptr; long zeroes, n; long i; (void)ndx; for (zeroes = 0 ; zeroes < size && !bytes[size - zeroes - 1] ; ++zeroes) ; if (zeroes == size) { out("{ 0 }"); return; } if (zeroes < 255 || zeroes * 4 < size) zeroes = 0; zeroes &= ~7; n = outstringsize((char const*)bytes, size); if (forcehex || n * 2 > size * 3) { beginblock(TRUE); for (i = 0 ; i < size - zeroes ; ++i) outf("0x%02X", bytes[i]); if (zeroes) outcomment(strf("0x00 x %d", zeroes)); endblock(); } else if (zeroes || bytes[size - 1]) { beginblock(TRUE); for (i = 0 ; i < size - zeroes ; ++i) outchar(bytes[i]); if (zeroes) outcomment(strf("0x00 x %ld", zeroes)); endblock(); } else { outstring((char const*)bytes, size - 1); } } /* The output function for an array of 16-bit values. The values are * printed in hexadecimal unless they are all relatively small. */ static void outhalves(void const *ptr, long size, int ndx) { Elf64_Half const *halves = ptr; long count = size / sizeof *halves; char fmtbuf[16]; char const *fmt = NULL; unsigned int max; long zeroes, i; (void)ndx; for (zeroes = 0 ; zeroes < count ; ++zeroes) if (halves[count - zeroes - 1]) break; if (zeroes == count) { out("{ 0 }"); return; } if (zeroes < 255 || zeroes * 4 < count) zeroes = 0; zeroes &= ~3; count -= zeroes; max = 0; for (i = 0 ; i < count ; ++i) { if (max < halves[i]) max = halves[i]; } fmt = max > 0xFF ? "0x%04X" : max > 99 ? "0x%02X" : "%u"; beginblock(TRUE); for (i = 0 ; i < count ; ++i) outf(fmt, halves[i]); if (zeroes) { sprintf(fmtbuf, "%s x %%ld", fmt); outcomment(strf(fmtbuf, 0, zeroes)); } endblock(); } /* The output function for an array of 32-bit values. */ static void outwords(void const *ptr, long size, int ndx) { Elf64_Word const *words = ptr; long count = size / sizeof *words; char fmtbuf[16]; char const *fmt = NULL; unsigned long max; long zeroes, i; (void)ndx; for (zeroes = 0 ; zeroes < count ; ++zeroes) if (words[count - zeroes - 1]) break; if (zeroes == count) { out("{ 0 }"); return; } if (zeroes < 255 || zeroes * 4 < count) zeroes = 0; zeroes &= ~3; count -= zeroes; max = 0; for (i = 0 ; i < count ; ++i) { if (max < words[i]) max = words[i]; } fmt = max > 0xFFFF ? "0x%08X" : max > 0x00FF ? "0x%04X" : max > 99 ? "0x%02X" : "%u"; beginblock(TRUE); for (i = 0 ; i < count ; ++i) outf(fmt, words[i]); if (zeroes) { sprintf(fmtbuf, "%s x %%ld", fmt); outcomment(strf(fmtbuf, 0, zeroes)); } endblock(); } /* The output function for an array of 64-bit values. */ static void outxwords(void const *ptr, long size, int ndx) { Elf64_Xword const *xwords = ptr; long count = size / sizeof *xwords; char fmtbuf[16]; char const *fmt = NULL; unsigned long max; long zeroes, i; (void)ndx; for (zeroes = 0 ; zeroes < count ; ++zeroes) if (xwords[count - zeroes - 1]) break; if (zeroes == count) { out("{ 0 }"); return; } if (zeroes < 255 || zeroes * 4 < count) zeroes = 0; zeroes &= ~3; count -= zeroes; max = 0; for (i = 0 ; i < count ; ++i) { if (max < xwords[i]) max = xwords[i]; } fmt = max > 0xFFFFFFFF ? "0x%016lX" : max > 0x0000FFFF ? "0x%08lX" : max > 0x000000FF ? "0x%04lX" : max > 99 ? "0x%02lX" : "%lu"; beginblock(TRUE); for (i = 0 ; i < count ; ++i) outf(fmt, xwords[i]); if (zeroes) { sprintf(fmtbuf, "%s x %%ld", fmt); outcomment(strf(fmtbuf, 0, zeroes)); } endblock(); } /* The output function for an ELF hash table. The hash table is an * array of 32-bit values. The first two array elements indicate the * length of the following subsections. Line breaks are inserted to * indicate where the subsections start and end. */ static void outhashtable(void const *ptr, long size, int ndx) { Elf64_Word const *entries = ptr; long count = size / sizeof *entries; long i; (void)ndx; beginblock(TRUE); if (count <= 2 || (long)(entries[0] + entries[1] + 2) != count) { for (i = 0 ; i < count ; ++i) outdec(entries[i]); } else { outdec(entries[0]); outdec(entries[1]); linebreak(); i = 2; if (entries[0] > 0) { for ( ; i < (long)(2 + entries[0]) ; ++i) outdec(entries[i]); linebreak(); } for ( ; i < count ; ++i) outdec(entries[i]); } endblock(); } /* The GNU hash table is an array of 32-bit values. (Although in a * 64-bit ELF file the mask subpart consists of 64-bit values. But an * array cannot change its type midway through, so in this case the * mask values are split across two array entries.) */ static void outgnuhash(void const *ptr, long size, int ndx) { Elf64_Word const *entries = ptr; long count = size / sizeof *entries; int buckets, masks; int i, n; (void)ndx; if (count < 4) { outwords(ptr, size, ndx); return; } buckets = entries[0]; masks = entries[2]; if (iself64()) masks *= 2; if (4 + masks + buckets > count) { outwords(ptr, size, ndx); return; } beginblock(TRUE); for (i = 0 ; i < 4 ; ++i) outdec(entries[i]); n = i; if (masks) { linebreak(); for (i = 0 ; i < masks ; ++i) outf("0x%08lX", entries[n + i]); n += i; } if (buckets) { linebreak(); for (i = 0 ; i < buckets ; ++i) outdec(entries[n + i]); n += i; } if (n < count) { linebreak(); for (i = n ; i < count ; ++i) outf("0x%08lX", entries[i]); } endblock(); } /* The output function for note sections. The format of a note section * varies with the type of note, the only constant part being that it * starts with an Elf*_Nhdr struct, and is usually followed by a * string. However, each subpart is guaranteed to be a multiple of 4 * bytes, so notes are displayed as arrays of 32-bit values. Line * breaks are inserted to indicate the beginning of a note header. * Note sections in core files are rather different, so in that case a * completely different function is called instead. */ void outnote(void const *ptr, long size, int ndx) { Elf64_Word const *words = ptr; long count = size / sizeof *words; long i; int namesize, descsize, tag; (void)ndx; if (iscorefile()) { iself64() ? outnote64(ptr, size, ndx) : outnote32(ptr, size, ndx); return; } beginblock(TRUE); i = 0; while (i < count) { namesize = (words[i] + 3) / 4; descsize = (words[i + 1] + 3) / 4; linebreak(); outdec(words[i++]); outdec(words[i++]); tag = words[i++]; outdefint(tag, "NT_GNU_"); while (namesize-- && i < count) outhex(words[i++]); if (descsize == 0) continue; #ifdef NT_GNU_ABI_TAG if (tag == NT_GNU_ABI_TAG) { outdefint(words[i++], "ELF_NOTE_OS_"); --descsize; } #endif while (descsize-- && i < count) outhex(words[i++]); } endblock(); } /* The output functions for each type of piece in a 32-bit ELF file. */ static void (*outputfunctions32[P_COUNT])(void const *, long, int) = { outbytes, /* P_UNCLAIMED */ outbytes, /* P_SECTION */ outbytes, /* P_BYTES */ outhalves, /* P_HALVES */ outwords, /* P_WORDS */ outxwords, /* P_XWORDS */ outaddr32, /* P_ADDRS */ outbytes, /* P_STRINGS */ outnote, /* P_NOTE */ outhashtable, /* P_HASH */ outgnuhash, /* P_GNUHASH */ outsym32, /* P_SYMTAB */ outsyminfo32, /* P_SYMINFO */ outrel32, /* P_REL */ outrela32, /* P_RELA */ outmove32, /* P_MOVE */ outdyn32, /* P_DYNAMIC */ outshdr32, /* P_SHDRTAB */ outphdr32, /* P_PHDRTAB */ outehdr32, /* P_EHDR */ outnothing /* P_NONEXISTENT */ }; /* The output functions for each type of piece in a 64-bit ELF file. */ static void (*outputfunctions64[P_COUNT])(void const*, long, int) = { outbytes, /* P_UNCLAIMED */ outbytes, /* P_SECTION */ outbytes, /* P_BYTES */ outhalves, /* P_HALVES */ outwords, /* P_WORDS */ outxwords, /* P_XWORDS */ outaddr64, /* P_ADDRS */ outbytes, /* P_STRINGS */ outnote, /* P_NOTE */ outhashtable, /* P_HASH */ outgnuhash, /* P_GNUHASH */ outsym64, /* P_SYMTAB */ outsyminfo64, /* P_SYMINFO */ outrel64, /* P_REL */ outrela64, /* P_RELA */ outmove64, /* P_MOVE */ outdyn64, /* P_DYNAMIC */ outshdr64, /* P_SHDRTAB */ outphdr64, /* P_PHDRTAB */ outehdr64, /* P_EHDR */ outnothing /* P_NONEXISTENT */ }; /* Calls the appropriate output function for the indicated type. */ void outtypedblock(int type, long offset, long size, int ndx) { void const *ptr; ptr = getptrto(offset, &size); if (iself64()) outputfunctions64[type](ptr, size, ndx); else outputfunctions32[type](ptr, size, ndx); } /* Outputs everything, from start to finish. */ void output(void) { out("#include \n"); out("#include \n"); out("\n"); outputaddresses(); outputenum(); outputstruct(); outputpieces(); }