commit 83b823d88eff2d07297b655dd003bf9e2e213067
parent e13f55bfbdf51e7981d053ebbbcec3f738b6110f
Author: sin <sin@2f30.org>
Date: Tue, 5 Mar 2013 17:51:34 +0000
memzap: Implement -s option
We can now lookup symbols in ELF files and trace them.
Diffstat:
M | commonvar.mk | | | 2 | +- |
M | memzap.c | | | 81 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- |
2 files changed, 73 insertions(+), 10 deletions(-)
diff --git a/commonvar.mk b/commonvar.mk
@@ -3,7 +3,7 @@ PREFIX ?= /usr/local
CC := $(CROSS_COMPILE)$(CC)
CFLAGS += -g -O3 -Wall -Wextra -Wunused -DVERSION=\"$(VER)\" $(INCS)
-LDFLAGS +=
+LDFLAGS += -lelf
INCS = -I/usr/local/include
LIBS = -L/usr/local/lib
diff --git a/memzap.c b/memzap.c
@@ -1,8 +1,12 @@
/* See LICENSE file for copyright and license details. */
+#include <libelf.h>
+#include <gelf.h>
+
#include "proto.h"
static int verbose = 0;
+static int fsymbol = 0;
static void
usage(const char *prog)
@@ -37,6 +41,11 @@ dump_base_image(const char *name, void *buf, size_t len)
close(fdmem);
}
+static Elf_Scn *scn;
+static Elf_Data *edata;
+static GElf_Sym sym;
+static GElf_Shdr shdr;
+
int
main(int argc, char *argv[])
{
@@ -55,6 +64,9 @@ main(int argc, char *argv[])
char mdiff_path[PATH_MAX - 1];
bool once = false;
uint64_t cycle = 0;
+ char *symbol = NULL, *tmp;
+ Elf *e;
+ Elf32_Word symbol_count, i;
while ((c = getopt(argc, argv, "hs:l:r:vV")) != -1) {
switch (c) {
@@ -74,7 +86,9 @@ main(int argc, char *argv[])
len = strtoul(optarg, NULL, 10);
break;
case 's':
- errx(1, "-s option is unimplemented");
+ fsymbol = 1;
+ symbol = strdup(optarg);
+ break;
case '?':
default:
return 1;
@@ -88,11 +102,60 @@ main(int argc, char *argv[])
return 1;
}
- if (!addr || !len)
- errx(1, "no memory region/len specified");
+ if (fsymbol) {
+ if (addr || len) {
+ errx(1, "You can't trace both a symbol and a region/length");
+ }
+ } else {
+ if (!addr || !len) {
+ errx(1, "no memory region/len specified");
+ }
+ }
+
+ if (fsymbol) {
+ if (elf_version(EV_CURRENT) == EV_NONE)
+ errx(1, "ELF library initialization failed: %s",
+ elf_errmsg(-1));
+
+ fd = open(*argv, O_RDONLY);
+ if (fd < 0)
+ errx(1, "%s: %s\n", *argv, strerror(errno));
+
+ e = elf_begin(fd, ELF_C_READ, NULL);
+ if (!e)
+ errx(1, "elf_begin() failed: %s",
+ elf_errmsg(-1));
+
+ while ((scn = elf_nextscn(e, scn))) {
+ gelf_getshdr(scn, &shdr);
+ if (shdr.sh_type == SHT_SYMTAB) {
+ edata = elf_getdata(scn, edata);
+ symbol_count = shdr.sh_size / shdr.sh_entsize;
+ for (i = 0; i < symbol_count; i++) {
+ gelf_getsym(edata, i, &sym);
+ tmp = elf_strptr(e, shdr.sh_link, sym.st_name);
+ if (!strcmp(symbol, tmp)) {
+ if (verbose > 0) {
+ printf("found symbol %s at %p\n",
+ symbol, (void *)sym.st_value);
+ }
+ addr = (void *)sym.st_value;
+ len = (size_t)sym.st_size;
+ break;
+ }
+ }
+ if (!addr || !len)
+ errx(1, "symbol %s could not be located", symbol);
+ free(symbol);
+ }
+ }
+
+ elf_end(e);
+ close(fd);
+ }
if (verbose > 0)
- printf("Base address: %p, length: %zu\n",
+ printf("base address: %p, length: %zu\n",
addr, len);
pid = fork();
@@ -109,13 +172,13 @@ main(int argc, char *argv[])
}
if (verbose > 0)
- printf("Mapping buffers into memory\n");
+ printf("mapping buffers into memory\n");
buf = map_buf(len);
buf_new = map_buf(len);
if (verbose > 0)
- printf("Single stepping child with pid %jd\n",
+ printf("single stepping child with pid %jd\n",
(intmax_t)pid);
wait(&stat);
@@ -152,11 +215,11 @@ main(int argc, char *argv[])
/* Build a memory region that tracks this buffer */
mr_old = build_mem_region(buf, len);
if (!mr_old)
- errx(1, "Failed to build memory region\n");
+ errx(1, "failed to build memory region\n");
/* Build an rbtree that tracks this memory region */
mt_old = build_mem_tree(mr_old);
if (!mt_old)
- errx(1, "Failed to build memory tree\n");
+ errx(1, "failed to build memory tree\n");
/* Single step the child in order to get the next
* generation */
@@ -176,7 +239,7 @@ main(int argc, char *argv[])
/* Build a memory region that tracks this buffer */
mr_new = build_mem_region(buf_new, len);
if (!mr_new)
- errx(1, "Failed to build memory region\n");
+ errx(1, "failed to build memory region\n");
/* Diff the original copy with the updated copy */
rdiff = diff_mem_region(mt_old, mr_new);