Print ELF header/segments/sections
authornorly <ny-git@enpas.org>
Fri, 25 Jan 2013 15:24:36 +0000 (15:24 +0000)
committernorly <ny-git@enpas.org>
Mon, 11 Feb 2013 01:24:36 +0000 (01:24 +0000)
19 files changed:
Makefile [new file with mode: 0644]
include/elfhandle.h [new file with mode: 0644]
include/libelfu/analysis.h [new file with mode: 0644]
include/libelfu/libelfu.h [new file with mode: 0644]
include/libelfu/lookup.h [new file with mode: 0644]
include/libelfu/types.h [new file with mode: 0644]
include/options.h [new file with mode: 0644]
include/printing.h [new file with mode: 0644]
src/analysis/segment-contains-section.c [new file with mode: 0644]
src/elfhandle.c [new file with mode: 0644]
src/lookup/first-section-in-segment.c [new file with mode: 0644]
src/lookup/last-section-in-segment.c [new file with mode: 0644]
src/lookup/section-by-name.c [new file with mode: 0644]
src/lookup/section-name.c [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/options.c [new file with mode: 0644]
src/printing/header.c [new file with mode: 0644]
src/printing/sections.c [new file with mode: 0644]
src/printing/segments.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..df5f59f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,46 @@
+PROJ := elfedit
+
+BUILDDIR   := build
+INCLUDEDIR := include
+SRCDIR     := src
+
+EXE     := $(BUILDDIR)/$(PROJ)
+HEADERS := $(shell find $(INCLUDEDIR)/ -iname "*.h")
+HEADERS += $(shell find $(SRCDIR)/ -iname "*.h")
+
+SOURCES := $(shell find $(SRCDIR)/ -iname "*.c")
+OBJS    := $(patsubst %.c, $(BUILDDIR)/%.o, $(SOURCES))
+
+INCLUDES := $(patsubst %, -I%, $(INCLUDEDIR) $(SRCDIR)) -I /usr/include/libelf
+CFLAGS   := -g -Wall
+LDFLAGS  := -lelf
+
+
+
+.PHONY: default
+default: $(EXE)
+
+
+
+$(EXE): $(OBJS)
+       @if [ ! -d $(BUILDDIR) ] ; then echo "Error: Build dir '$(BUILDDIR)' does not exist." ; false ; fi
+       gcc $(LDFLAGS) -o $@ $^
+
+
+$(BUILDDIR)/$(SRCDIR)/%.o: $(SRCDIR)/%.c $(HEADERS)
+       @if [ ! -d $(dir $@) ] ; then mkdir -p $(dir $@) ; fi
+       gcc $(INCLUDES) $(CFLAGS) -c -o $@ $<
+
+
+.PHONY: clean
+clean:
+       rm -f $(STATICLIB)
+       rm -f $(OBJS)
+       rm -f $(TESTEXES)
+       rm -rf $(BUILDDIR)/
+
+
+.PHONY: distclean
+distclean: clean
+       find . -xdev -name "*~" -exec rm {} \;
+       find . -xdev -name "core" -exec rm {} \;
diff --git a/include/elfhandle.h b/include/elfhandle.h
new file mode 100644 (file)
index 0000000..b1a92ea
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __ELFHANDLE_H__
+#define __ELFHANDLE_H__
+
+#include <libelf.h>
+
+typedef struct {
+  int fd;
+  Elf *e;
+} ELFHandles;
+
+
+void openElf(ELFHandles *h, char *fn, Elf_Cmd elfmode);
+void closeElf(ELFHandles *h);
+
+#endif
diff --git a/include/libelfu/analysis.h b/include/libelfu/analysis.h
new file mode 100644 (file)
index 0000000..80ec251
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __LIBELFU_ANALYSIS_H_
+#define __LIBELFU_ANALYSIS_H_
+
+#include <libelf.h>
+#include <gelf.h>
+
+#include <libelfu/types.h>
+
+ELFU_BOOL elfu_segmentContainsSection(GElf_Phdr *phdr, Elf_Scn *scn);
+
+#endif
diff --git a/include/libelfu/libelfu.h b/include/libelfu/libelfu.h
new file mode 100644 (file)
index 0000000..1c40541
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __LIBELFU_LIBELFU_H__
+#define __LIBELFU_LIBELFU_H__
+
+
+#include <libelfu/types.h>
+
+#include <libelfu/analysis.h>
+#include <libelfu/lookup.h>
+
+
+#endif
diff --git a/include/libelfu/lookup.h b/include/libelfu/lookup.h
new file mode 100644 (file)
index 0000000..2cca5df
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __LIBELFU_LOOKUP_H_
+#define __LIBELFU_LOOKUP_H_
+
+#include <libelf.h>
+#include <gelf.h>
+
+#include <libelfu/types.h>
+
+char* elfu_sectionName(Elf *e, Elf_Scn *scn);
+Elf_Scn* elfu_sectionByName(Elf *e, char *name);
+Elf_Scn* elfu_firstSectionInSegment(Elf *e, GElf_Phdr *phdr);
+Elf_Scn* elfu_lastSectionInSegment(Elf *e, GElf_Phdr *phdr);
+
+#endif
diff --git a/include/libelfu/types.h b/include/libelfu/types.h
new file mode 100644 (file)
index 0000000..6ffdd84
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __LIBELFU_TYPES_H__
+#define __LIBELFU_TYPES_H__
+
+typedef enum {
+  ELFU_ERROR = -1,
+  ELFU_FALSE = 0,
+  ELFU_TRUE = 1
+} ELFU_BOOL;
+
+#endif
diff --git a/include/options.h b/include/options.h
new file mode 100644 (file)
index 0000000..f39f01e
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __OPTIONS_H__
+#define __OPTIONS_H__
+
+
+typedef struct {
+  char *fnInput;
+  char *fnOutput;
+  int printHeader;
+  int printSegments;
+  int printSections;
+} CLIOpts;
+
+
+void parseOptions(CLIOpts *opts, int argc, char **argv);
+
+#endif
diff --git a/include/printing.h b/include/printing.h
new file mode 100644 (file)
index 0000000..bda2fc1
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __PRINTING_H__
+#define __PRINTING_H__
+
+#include <libelf.h>
+
+
+void printHeader(Elf *e);
+
+void printSegmentsWithSection(Elf *e, Elf_Scn *scn);
+void printSection(Elf *e, Elf_Scn *scn);
+void printSections(Elf *e);
+
+char* segmentTypeStr(size_t pt);
+void printSectionsInSegment(Elf *e, GElf_Phdr *phdr);
+void printSegments(Elf *e);
+
+
+#endif
diff --git a/src/analysis/segment-contains-section.c b/src/analysis/segment-contains-section.c
new file mode 100644 (file)
index 0000000..dc3269d
--- /dev/null
@@ -0,0 +1,26 @@
+#include <libelf.h>
+#include <gelf.h>
+
+#include <libelfu/libelfu.h>
+
+
+ELFU_BOOL elfu_segmentContainsSection(GElf_Phdr *phdr, Elf_Scn *scn)
+{
+  GElf_Shdr shdr;
+
+
+  if (gelf_getshdr(scn, &shdr) != &shdr) {
+    return ELFU_ERROR;
+  }
+
+  size_t secStart = shdr.sh_offset;
+  size_t secEnd   = shdr.sh_offset + shdr.sh_size;
+  size_t segStart = phdr->p_offset;
+  size_t segEnd   = phdr->p_offset + phdr->p_memsz;
+
+  if (secStart < segStart || secEnd > segEnd) {
+    return ELFU_FALSE;
+  }
+
+  return ELFU_TRUE;
+}
diff --git a/src/elfhandle.c b/src/elfhandle.c
new file mode 100644 (file)
index 0000000..a17216d
--- /dev/null
@@ -0,0 +1,74 @@
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libelf.h>
+
+#include "elfhandle.h"
+
+
+void openElf(ELFHandles *h, char *fn, Elf_Cmd elfmode)
+{
+  int openflags = 0;
+  int openmode = 0;
+
+  h->e = NULL;
+
+  switch(elfmode) {
+    case ELF_C_READ:
+      openflags = O_RDONLY;
+      break;
+    case ELF_C_WRITE:
+      openflags = O_WRONLY | O_CREAT;
+      openmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+      break;
+    case ELF_C_RDWR:
+      openflags = O_RDWR;
+      break;
+    default:
+      return;
+  }
+
+
+  h->fd = open(fn, openflags, openmode);
+  if (h->fd < 0) {
+    fprintf(stderr, "Cannot open %s: %s\n", fn, strerror(errno));
+    return;
+  }
+
+  h->e = elf_begin(h->fd, elfmode, NULL);
+  if (!h->e) {
+    fprintf(stderr, "elf_begin() failed on %s: %s\n", fn, elf_errmsg(-1));
+    goto ERR;
+  }
+
+  if (elfmode == ELF_C_READ || elfmode == ELF_C_RDWR) {
+    if (elf_kind(h->e) != ELF_K_ELF) {
+      fprintf(stderr, "Not an ELF object: %s", fn);
+      goto ERR;
+    }
+  }
+
+  return;
+
+ERR:
+  if (h->e) {
+    elf_end(h->e);
+    h->e = NULL;
+  }
+  close(h->fd);
+}
+
+
+void closeElf(ELFHandles *h)
+{
+  if (h->e) {
+    elf_end(h->e);
+    close(h->fd);
+    h->e = NULL;
+  }
+}
diff --git a/src/lookup/first-section-in-segment.c b/src/lookup/first-section-in-segment.c
new file mode 100644 (file)
index 0000000..b66c518
--- /dev/null
@@ -0,0 +1,34 @@
+#include <libelf.h>
+#include <gelf.h>
+
+#include <libelfu/libelfu.h>
+
+
+/*
+ * Returns the section that starts at the same point in the file as
+ * the segment AND is wholly contained in the memory image.
+ *
+ * If no section fits, NULL is returned.
+ */
+Elf_Scn* elfu_firstSectionInSegment(Elf *e, GElf_Phdr *phdr)
+{
+  Elf_Scn *scn;
+
+  scn = elf_getscn(e, 1);
+  while (scn) {
+    GElf_Shdr shdr;
+
+    if (gelf_getshdr(scn, &shdr) != &shdr) {
+      return NULL;
+    }
+
+    if (shdr.sh_offset == phdr->p_offset
+        && elfu_segmentContainsSection(phdr, scn) == ELFU_TRUE) {
+      return scn;
+    }
+
+    scn = elf_nextscn(e, scn);
+  }
+
+  return NULL;
+}
diff --git a/src/lookup/last-section-in-segment.c b/src/lookup/last-section-in-segment.c
new file mode 100644 (file)
index 0000000..0e78263
--- /dev/null
@@ -0,0 +1,49 @@
+#include <libelf.h>
+#include <gelf.h>
+
+#include <libelfu/libelfu.h>
+
+
+/*
+ * Returns the first section that  is contained in the segment and
+ * ends as close to its memory image of as possible (the "last"
+ * section in the segment).
+ *
+ * If no section fits, NULL is returned.
+ */
+Elf_Scn* elfu_lastSectionInSegment(Elf *e, GElf_Phdr *phdr)
+{
+  Elf_Scn *last = NULL;
+  Elf_Scn *scn;
+
+
+  scn = elf_getscn(e, 1);
+  while (scn) {
+    if (elfu_segmentContainsSection(phdr, scn) == ELFU_TRUE) {
+      if (!last) {
+        last = scn;
+      } else {
+        GElf_Shdr shdrOld;
+        GElf_Shdr shdrNew;
+
+        if (gelf_getshdr(last, &shdrOld) != &shdrOld) {
+          continue;
+        }
+
+        if (gelf_getshdr(scn, &shdrNew) != &shdrNew) {
+          continue;
+        }
+
+        if (shdrNew.sh_offset + shdrNew.sh_size
+            > shdrOld.sh_offset + shdrOld.sh_size) {
+          // TODO: Check (leftover space in memory image) < (p_align)
+          last = scn;
+        }
+      }
+    }
+
+    scn = elf_nextscn(e, scn);
+  }
+
+  return last;
+}
diff --git a/src/lookup/section-by-name.c b/src/lookup/section-by-name.c
new file mode 100644 (file)
index 0000000..1697140
--- /dev/null
@@ -0,0 +1,39 @@
+#include <string.h>
+
+#include <libelf.h>
+#include <gelf.h>
+
+#include <libelfu/libelfu.h>
+
+
+Elf_Scn* elfu_sectionByName(Elf *e, char *name)
+{
+  size_t shstrndx;
+  Elf_Scn *scn;
+
+  if (elf_getshdrstrndx(e, &shstrndx) != 0) {
+    return NULL;
+  }
+
+  scn = elf_getscn(e, 1);
+  while (scn) {
+    GElf_Shdr shdr;
+    char *curname;
+
+    if (gelf_getshdr(scn, &shdr) != &shdr) {
+      return NULL;
+    }
+
+    /* elf_strptr returns NULL if there was an error */
+    curname = elf_strptr(e, shstrndx, shdr.sh_name);
+
+    /* strcmp... but we really have no bounds on the lengths here */
+    if (!strcmp(curname, name)) {
+      return scn;
+    }
+
+    scn = elf_nextscn(e, scn);
+  }
+
+  return NULL;
+}
diff --git a/src/lookup/section-name.c b/src/lookup/section-name.c
new file mode 100644 (file)
index 0000000..d3748f9
--- /dev/null
@@ -0,0 +1,22 @@
+#include <libelf.h>
+#include <gelf.h>
+
+#include <libelfu/libelfu.h>
+
+
+char* elfu_sectionName(Elf *e, Elf_Scn *scn)
+{
+  size_t shstrndx;
+  GElf_Shdr shdr;
+
+  if (elf_getshdrstrndx(e, &shstrndx) != 0) {
+    return NULL;
+  }
+
+  if (gelf_getshdr(scn, &shdr) != &shdr) {
+    return NULL;
+  }
+
+  /* elf_strptr returns NULL if there was an error */
+  return elf_strptr(e, shstrndx, shdr.sh_name);
+}
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..9791feb
--- /dev/null
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <getopt.h>
+#include <libelf.h>
+#include <gelf.h>
+
+#include "elfhandle.h"
+#include "options.h"
+#include "printing.h"
+
+
+int main(int argc, char **argv)
+{
+  CLIOpts opts = { 0 };
+  ELFHandles hIn = { 0 };
+  ELFHandles hOut = { 0 };
+  int exitval = EXIT_SUCCESS;
+
+  /* Is libelf alive and well? */
+  if (elf_version(EV_CURRENT) == EV_NONE) {
+    fprintf(stderr, "libelf init error: %s\n", elf_errmsg(-1));
+  }
+
+
+  /* Parse and validate user input */
+  parseOptions(&opts, argc, argv);
+
+
+  /* Open input/output files */
+  openElf(&hIn, opts.fnInput, ELF_C_READ);
+  if (!hIn.e) {
+    exitval = EXIT_FAILURE;
+    goto EXIT;
+  }
+
+  if (opts.fnOutput) {
+    openElf(&hOut, opts.fnOutput, ELF_C_WRITE);
+    if (!hOut.e) {
+      exitval = EXIT_FAILURE;
+      goto EXIT;
+    }
+  }
+
+
+  /* Now that we have a (hopefully) sane environment, execute commands */
+  if (opts.printHeader) {
+    printHeader(hIn.e);
+  }
+
+  if (opts.printSegments) {
+    printSegments(hIn.e);
+  }
+
+  if (opts.printSections) {
+    printSections(hIn.e);
+  }
+
+
+
+EXIT:
+  if (hOut.e) {
+    if (elf_update(hOut.e, ELF_C_WRITE) < 0) {
+      fprintf(stderr, "elf_update() failed: %s\n", elf_errmsg(-1));
+    }
+    closeElf(&hOut);
+  }
+
+  if (hIn.e) {
+    closeElf(&hIn);
+  }
+
+  return (exitval);
+}
diff --git a/src/options.c b/src/options.c
new file mode 100644 (file)
index 0000000..014a1f2
--- /dev/null
@@ -0,0 +1,81 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "options.h"
+
+
+static void printUsage(char *progname)
+{
+  printf("Usage: %s [OPTIONS] <elf-file>\n", progname);
+  printf("\n"
+          "Options:\n"
+          "  -h, --help                 Print this help message\n"
+          "  -o, --output               Where to write the modified ELF file to\n"
+          "\n"
+          "      --print-header         Print ELF header\n"
+          "      --print-segments       Print program headers\n"
+          "      --print-sections       Print sections\n"
+          "\n");
+}
+
+
+
+void parseOptions(CLIOpts *opts, int argc, char **argv)
+{
+  char *progname = argv[0];
+  int c;
+  int option_index = 0;
+
+  static struct option long_options[] = {
+    {"help", 0, 0, 'h'},
+    {"output", 1, 0, 'o'},
+    {"print-header", 0, 0, 10001},
+    {"print-segments", 0, 0, 10002},
+    {"print-sections", 0, 0, 10003},
+    {NULL, 0, NULL, 0}
+  };
+
+  while ((c = getopt_long(argc, argv, "e:ho:",
+                          long_options, &option_index)) != -1) {
+    switch (c) {
+      case 'h':
+        printUsage(progname);
+        exit(EXIT_SUCCESS);
+      case 'o':
+        opts->fnOutput = optarg;
+        break;
+      case 10001:
+        opts->printHeader = 1;
+        break;
+      case 10002:
+        opts->printSegments = 1;
+        break;
+      case 10003:
+        opts->printSections = 1;
+        break;
+      case '?':
+      default:
+        goto USAGE;
+    }
+  }
+
+  while (optind < argc) {
+    if (!opts->fnInput) {
+      opts->fnInput = argv[optind];
+    }
+    optind++;
+  }
+
+  if (!opts->fnInput) {
+    fprintf(stderr, "Error: No input file specified.\n\n");
+    goto USAGE;
+  }
+
+  return;
+
+USAGE:
+  printUsage(progname);
+  exit(1);
+}
diff --git a/src/printing/header.c b/src/printing/header.c
new file mode 100644 (file)
index 0000000..33f7bdb
--- /dev/null
@@ -0,0 +1,62 @@
+#include <stdio.h>
+
+#include <libelf.h>
+#include <gelf.h>
+
+
+void printHeader(Elf *e)
+{
+  GElf_Ehdr ehdr;
+  int elfclass;
+  size_t shdrnum, shdrstrndx, phdrnum;
+
+
+  printf("ELF header:\n");
+
+
+  elfclass = gelf_getclass(e);
+  if (elfclass == ELFCLASSNONE) {
+    fprintf(stderr, "getclass() failed: %s\n", elf_errmsg(-1));
+  }
+  printf(" * %d-bit ELF object\n", elfclass == ELFCLASS32 ? 32 : 64);
+
+
+  if (!gelf_getehdr(e, &ehdr)) {
+    fprintf(stderr, "getehdr() failed: %s.", elf_errmsg(-1));
+    return;
+  }
+
+  printf(" *     type  machine  version    entry    phoff    shoff    flags   ehsize phentsize shentsize\n");
+  printf("   %8jx %8jx %8jx %8jx %8jx %8jx %8jx %8jx %9jx %9jx\n",
+          (uintmax_t) ehdr.e_type,
+          (uintmax_t) ehdr.e_machine,
+          (uintmax_t) ehdr.e_version,
+          (uintmax_t) ehdr.e_entry,
+          (uintmax_t) ehdr.e_phoff,
+          (uintmax_t) ehdr.e_shoff,
+          (uintmax_t) ehdr.e_flags,
+          (uintmax_t) ehdr.e_ehsize,
+          (uintmax_t) ehdr.e_phentsize,
+          (uintmax_t) ehdr.e_shentsize);
+
+
+  if (elf_getshdrnum(e, &shdrnum) != 0) {
+    fprintf(stderr, "getshdrnum() failed: %s\n", elf_errmsg(-1));
+  } else {
+    printf(" * (shnum):    %u\n", shdrnum);
+  }
+
+  if (elf_getshdrstrndx(e, &shdrstrndx) != 0) {
+    fprintf(stderr, "getshdrstrndx() failed: %s\n", elf_errmsg(-1));
+  } else {
+    printf(" * (shstrndx): %u\n", shdrstrndx);
+  }
+
+  if (elf_getphdrnum(e, &phdrnum) != 0) {
+    fprintf(stderr, "getphdrnum() failed: %s\n", elf_errmsg(-1));
+  } else {
+    printf(" * (phnum):    %u\n", phdrnum);
+  }
+
+  printf("\n");
+}
diff --git a/src/printing/sections.c b/src/printing/sections.c
new file mode 100644 (file)
index 0000000..6241a73
--- /dev/null
@@ -0,0 +1,60 @@
+#include <stdio.h>
+
+#include <libelf.h>
+#include <gelf.h>
+
+#include <libelfu/libelfu.h>
+#include "printing.h"
+
+
+void printSegmentsWithSection(Elf *e, Elf_Scn *scn)
+{
+  GElf_Phdr phdr;
+  int i;
+  size_t n;
+
+
+  if (elf_getphdrnum(e, &n)) {
+    fprintf(stderr, "elf_getphdrnum() failed: %s\n", elf_errmsg(-1));
+    return;
+  }
+
+  for (i = 0; i < n; i++) {
+    ELFU_BOOL isInSeg;
+
+    if (gelf_getphdr(e, i, &phdr) != &phdr) {
+      fprintf(stderr, "getphdr() failed for #%d: %s\n", i, elf_errmsg(-1));
+      continue;
+    }
+
+    isInSeg = elfu_segmentContainsSection(&phdr, scn);
+    if (isInSeg == ELFU_TRUE) {
+      printf("     %d %s\n", i, segmentTypeStr(phdr.p_type));
+    }
+  }
+}
+
+
+void printSection(Elf *e, Elf_Scn *scn)
+{
+  printf("  %jd: %s\n",
+          (uintmax_t) elf_ndxscn(scn),
+          elfu_sectionName(e, scn));
+}
+
+
+void printSections(Elf *e)
+{
+  Elf_Scn *scn;
+
+  printf("Sections:\n");
+
+  scn = elf_getscn(e, 0);
+
+  while (scn) {
+    printSection(e, scn);
+    //printSegmentsWithSection(e, scn);
+
+    scn = elf_nextscn(e, scn);
+  }
+}
diff --git a/src/printing/segments.c b/src/printing/segments.c
new file mode 100644 (file)
index 0000000..6d8cac7
--- /dev/null
@@ -0,0 +1,76 @@
+#include <stdio.h>
+
+#include <libelf.h>
+#include <gelf.h>
+
+#include <libelfu/libelfu.h>
+
+
+static char *ptstr[] = {"NULL", "LOAD", "DYNAMIC", "INTERP", "NOTE", "SHLIB", "PHDR", "TLS", "NUM"};
+
+
+char* segmentTypeStr(size_t pt)
+{
+  if (pt >= 0 && pt <= PT_NUM) {
+    return ptstr[pt];
+  }
+
+  return "-?-";
+}
+
+
+void printSectionsInSegment(Elf *e, GElf_Phdr *phdr)
+{
+  Elf_Scn *scn;
+
+  scn = elf_getscn(e, 0);
+
+  while (scn) {
+    ELFU_BOOL isInSeg;
+
+    isInSeg = elfu_segmentContainsSection(phdr, scn);
+    if (isInSeg == ELFU_TRUE) {
+      printf("       %10u %s\n", elf_ndxscn(scn), elfu_sectionName(e, scn));
+    }
+
+    scn = elf_nextscn(e, scn);
+  }
+}
+
+
+void printSegments(Elf *e)
+{
+  size_t i, n;
+
+  if (elf_getphdrnum(e, &n)) {
+    fprintf(stderr, "elf_getphdrnum() failed: %s.", elf_errmsg(-1));
+  }
+
+  printf("Segments:\n");
+  printf("      #   typeStr     type   offset    vaddr    paddr   filesz    memsz    flags    align\n");
+
+  for (i = 0; i < n; i++) {
+    GElf_Phdr phdr;
+
+    if (gelf_getphdr(e, i, &phdr) != &phdr) {
+      fprintf(stderr, "getphdr() failed for #%d: %s.", i, elf_errmsg(-1));
+      continue;
+    }
+
+    printf(" * %4d: %8s ", i, segmentTypeStr(phdr.p_type));
+
+    printf("%8jx %8jx %8jx %8jx %8jx %8jx %8jx %8jx\n",
+            (uintmax_t) phdr.p_type,
+            (uintmax_t) phdr.p_offset,
+            (uintmax_t) phdr.p_vaddr,
+            (uintmax_t) phdr.p_paddr,
+            (uintmax_t) phdr.p_filesz,
+            (uintmax_t) phdr.p_memsz,
+            (uintmax_t) phdr.p_flags,
+            (uintmax_t) phdr.p_align);
+
+    printSectionsInSegment(e, &phdr);
+  }
+
+  printf("\n");
+}