diff options
Diffstat (limited to 'usr/src/lib/libsaveargs/tests/dump/dump.c')
-rw-r--r-- | usr/src/lib/libsaveargs/tests/dump/dump.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/usr/src/lib/libsaveargs/tests/dump/dump.c b/usr/src/lib/libsaveargs/tests/dump/dump.c new file mode 100644 index 0000000000..7b4a628d4a --- /dev/null +++ b/usr/src/lib/libsaveargs/tests/dump/dump.c @@ -0,0 +1,167 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2011, Joyent, Inc. All rights reserved. + * Copyright (c) 2011, Robert Mustacchi, Inc. All rights reserved. + * Copyright 2013, Richard Lowe. + */ + +#include <err.h> +#include <fcntl.h> +#include <gelf.h> +#include <libctf.h> +#include <saveargs.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> +#include <unistd.h> + +extern const char *__progname; + +typedef struct symtab_sym { + GElf_Sym ss_sym; + char *ss_name; + ctf_funcinfo_t ss_finfo; + uint8_t *ss_data; + size_t ss_size; +} symtab_sym_t; + +static void +walk_symtab(Elf *elf, char *fname, ctf_file_t *fp, + void (*callback)(ctf_file_t *, symtab_sym_t *)) +{ + Elf_Scn *stab = NULL; + Elf_Scn *text = NULL; + Elf_Data *stabdata = NULL; + Elf_Data *textdata = NULL; + GElf_Ehdr ehdr; + GElf_Shdr stabshdr; + GElf_Shdr textshdr; + int foundtext = 0, foundstab = 0; + symtab_sym_t ss; + + if ((gelf_getehdr(elf, &ehdr)) == NULL) + errx(1, "could not read ELF header from %s\n", + fname); + + while ((stab = elf_nextscn(elf, stab)) != NULL) { + (void) gelf_getshdr(stab, &stabshdr); + + if (stabshdr.sh_type == SHT_SYMTAB) { + foundstab = 1; + break; + } + } + + while ((text = elf_nextscn(elf, text)) != NULL) { + (void) gelf_getshdr(text, &textshdr); + + if (strcmp(".text", elf_strptr(elf, + ehdr.e_shstrndx, (size_t)textshdr.sh_name)) == 0) { + foundtext = 1; + break; + } + } + + if (!foundstab || !foundtext) + return; + + stabdata = elf_getdata(stab, NULL); + textdata = elf_rawdata(text, NULL); + for (unsigned symdx = 0; + symdx < (stabshdr.sh_size / stabshdr.sh_entsize); + symdx++) { + (void) gelf_getsym(stabdata, symdx, &ss.ss_sym); + + if ((GELF_ST_TYPE(ss.ss_sym.st_info) != STT_FUNC) || + (ss.ss_sym.st_shndx == SHN_UNDEF)) + continue; + + ss.ss_name = elf_strptr(elf, stabshdr.sh_link, + ss.ss_sym.st_name); + ss.ss_data = ((uint8_t *)(textdata->d_buf)) + + (ss.ss_sym.st_value - textshdr.sh_addr); + + if (ctf_func_info(fp, symdx, &ss.ss_finfo) == CTF_ERR) { + fprintf(stderr, "failed to get funcinfo for: %s\n", + ss.ss_name); + continue; + } + + (void) callback(fp, &ss); + } +} + +void +check_sym(ctf_file_t *ctfp, symtab_sym_t *ss) +{ + int rettype = ctf_type_kind(ctfp, ss->ss_finfo.ctc_return); + int start_index = 0; + + if (ss->ss_finfo.ctc_argc == 0) /* No arguments, no point */ + return; + + if (((rettype == CTF_K_STRUCT) || (rettype == CTF_K_UNION)) && + ctf_type_size(ctfp, ss->ss_finfo.ctc_return) > 16) + start_index = 1; + + if (saveargs_has_args(ss->ss_data, ss->ss_sym.st_size, + ss->ss_finfo.ctc_argc, start_index) != SAVEARGS_NO_ARGS) + printf("%s has %d saved args\n", ss->ss_name, + ss->ss_finfo.ctc_argc); +} + +int +main(int argc, char **argv) +{ + Elf *elf; + ctf_file_t *ctfp; + int errp, fd; + + if (ctf_version(CTF_VERSION) == -1) + errx(1, "mismatched libctf versions\n"); + + if (elf_version(EV_CURRENT) == EV_NONE) + errx(1, "mismatched libelf versions\n"); + + if (argc != 2) + errx(2, "usage: %s <file>\n", __progname); + + if ((ctfp = ctf_open(argv[1], &errp)) == NULL) + errx(1, "failed to ctf_open file: %s: %s\n", argv[1], + ctf_errmsg(errp)); + + if ((fd = open(argv[1], O_RDONLY)) == -1) + errx(1, "could not open %s\n", argv[1]); + + if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) + errx(1, "could not interpret ELF from %s\n", + argv[1]); + + walk_symtab(elf, argv[1], ctfp, check_sym); + + (void) elf_end(elf); + (void) close(fd); + + return (0); +} |