memzap

replay memory writes
git clone git://git.2f30.org/memzap
Log | Files | Refs | README | LICENSE

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:
Mcommonvar.mk | 2+-
Mmemzap.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);