Browse Source

Initial commit

master
Denis Tereshkin 7 months ago
commit
8595e20e2c
  1. 31
      CMakeLists.txt
  2. 331
      src/ftracetool.c
  3. 6
      src/version.h

31
CMakeLists.txt

@ -0,0 +1,31 @@
cmake_minimum_required(VERSION 3.10)
project(ftracetool C)
set(CMAKE_C_STANDARD 23)
set(CMAKE_C_STANDARD_REQUIRED ON)
find_package(PkgConfig)
pkg_search_module(LIBELF REQUIRED libelf)
pkg_search_module(CHIBI_SCHEME REQUIRED chibi-scheme)
if(NOT CHIBI_SCHEME_FOUND)
message(FATAL_ERROR "chibi-scheme not found!")
endif()
if(NOT LIBELF_FOUND)
message(FATAL_ERROR "libelf not found!")
endif()
file(GLOB SOURCES "src/*.c")
message(STATUS "Libelf include dirs: ${LIBELF_INCLUDE_DIRS}")
message(STATUS "Libelf libraries: ${LIBELF_LIBRARIES}")
message(STATUS "Chibi-scheme include dirs: ${CHIBI_SCHEME_INCLUDE_DIRS}")
message(STATUS "Chibi-scheme libraries: ${CHIBI_SCHEME_LIBRARIES}")
add_executable(ftracetool ${SOURCES})
target_include_directories(ftracetool PRIVATE ${LIBELF_INCLUDE_DIRS} ${CHIBI_SCHEME_INCLUDE_DIRS})
target_link_libraries(ftracetool PRIVATE ${LIBELF_LIBRARIES} ${CHIBI_SCHEME_LIBRARIES})

331
src/ftracetool.c

@ -0,0 +1,331 @@
#include <chibi/sexp.h>
#include <elf.h>
#include <fcntl.h>
#include <gelf.h>
#include <libelf.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <chibi/eval.h>
#include "version.h"
#define CLEANUP(f) __attribute__((cleanup(f)))
static void show_version()
{
printf("ftracetool v%s\n", VERSION_STRING);
}
static void show_usage()
{
printf("ftracetool v%s\n \
-s Show symbols in elf file\n \
-v Show version\n \
-h Show help\n",
VERSION_STRING);
}
static void close_fd_ptr(const int *const fd)
{
close(*fd);
}
unsigned long lookup_symbol_in_file(const char *const filename,
const char *const symbol)
{
Elf *elf = NULL;
Elf_Scn *scn = NULL;
Elf_Data *data = NULL;
GElf_Shdr shdr = {};
size_t strtabndx = 0;
int const fd CLEANUP(close_fd_ptr) = open(filename, O_RDONLY);
if (fd == -1)
{
perror("open() failed");
return EXIT_FAILURE;
}
(void)elf_version(EV_CURRENT);
if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
{
fprintf(stderr, "elf_begin() failed: %s\n", elf_errmsg(elf_errno()));
return EXIT_FAILURE;
}
while ((scn = elf_nextscn(elf, scn)) != NULL)
{
if (gelf_getshdr(scn, &shdr) != &shdr)
{
fprintf(
stderr, "gelf_getshdr() failed: %s\n", elf_errmsg(elf_errno()));
continue;
}
if (shdr.sh_type != SHT_SYMTAB && shdr.sh_type != SHT_DYNSYM)
{
continue;
}
strtabndx = shdr.sh_link;
Elf_Scn *const strtab_scn = elf_getscn(elf, strtabndx);
if (!strtab_scn)
{
fprintf(
stderr, "elf_getscn() failed %s\n", elf_errmsg(elf_errno()));
continue;
}
Elf_Data *const strtab_data = elf_getdata(strtab_scn, NULL);
if (!strtab_data || !strtab_data->d_buf)
{
fprintf(
stderr, "elf_getdata() failed %s\n", elf_errmsg(elf_errno()));
continue;
}
data = elf_getdata(scn, NULL);
if (!data)
{
continue;
}
size_t const count = (shdr.sh_size / shdr.sh_entsize);
for (size_t i = 0; i < count; i++)
{
GElf_Sym sym = {};
if (gelf_getsym(data, i, &sym) != &sym)
{
continue;
}
if (sym.st_name == 0 || sym.st_value == 0)
{
continue;
}
const char *name = (const char *)strtab_data->d_buf + sym.st_name;
if (strcmp(name, symbol) == 0)
{
return sym.st_value;
}
}
}
elf_end(elf);
return -1;
}
static int do_show_symbols_in_file(const char *const filename)
{
Elf *elf = NULL;
Elf_Scn *scn = NULL;
Elf_Data *data = NULL;
GElf_Shdr shdr = {};
size_t strtabndx = 0;
int const fd CLEANUP(close_fd_ptr) = open(filename, O_RDONLY);
if (fd == -1)
{
perror("open() failed");
return EXIT_FAILURE;
}
(void)elf_version(EV_CURRENT);
if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
{
fprintf(stderr, "elf_begin() failed: %s\n", elf_errmsg(elf_errno()));
return EXIT_FAILURE;
}
while ((scn = elf_nextscn(elf, scn)) != NULL)
{
if (gelf_getshdr(scn, &shdr) != &shdr)
{
fprintf(
stderr, "gelf_getshdr() failed: %s\n", elf_errmsg(elf_errno()));
continue;
}
if (shdr.sh_type != SHT_SYMTAB && shdr.sh_type != SHT_DYNSYM)
{
continue;
}
strtabndx = shdr.sh_link;
Elf_Scn *const strtab_scn = elf_getscn(elf, strtabndx);
if (!strtab_scn)
{
fprintf(
stderr, "elf_getscn() failed %s\n", elf_errmsg(elf_errno()));
continue;
}
Elf_Data *const strtab_data = elf_getdata(strtab_scn, NULL);
if (!strtab_data || !strtab_data->d_buf)
{
fprintf(
stderr, "elf_getdata() failed %s\n", elf_errmsg(elf_errno()));
continue;
}
data = elf_getdata(scn, NULL);
if (!data)
{
continue;
}
size_t const count = (shdr.sh_size / shdr.sh_entsize);
for (size_t i = 0; i < count; i++)
{
GElf_Sym sym = {};
if (gelf_getsym(data, i, &sym) != &sym)
{
continue;
}
if (sym.st_name == 0 || sym.st_value == 0)
{
continue;
}
const char *name = (const char *)strtab_data->d_buf + sym.st_name;
printf("0x%08lx %s\n", (unsigned long)sym.st_value, name);
}
}
elf_end(elf);
return EXIT_SUCCESS;
}
static sexp sexp_lookup_symbol_in_file_stub(
sexp ctx, sexp self, sexp_sint_t n, sexp arg0, sexp arg1)
{
sexp res;
if (!sexp_stringp(arg0))
return sexp_type_exception(ctx, self, SEXP_STRING, arg0);
if (!sexp_stringp(arg1))
return sexp_type_exception(ctx, self, SEXP_STRING, arg1);
res = sexp_make_unsigned_integer(
ctx,
lookup_symbol_in_file(sexp_string_data(arg0), sexp_string_data(arg1)));
return res;
}
static int register_ftracetool_api(sexp ctx)
{
sexp_gc_var1(op);
sexp_gc_preserve1(ctx, op);
op = sexp_define_foreign(ctx,
sexp_context_env(ctx),
"lookup-symbol-in-file",
2,
sexp_lookup_symbol_in_file_stub);
if (sexp_opcodep(op))
{
sexp_opcode_return_type(op) = sexp_make_fixnum(SEXP_FIXNUM);
sexp_opcode_arg1_type(op) = sexp_make_fixnum(SEXP_STRING);
sexp_opcode_arg2_type(op) = sexp_make_fixnum(SEXP_STRING);
}
sexp_gc_release3(ctx);
return 0;
}
static int do_execute_script(const char *const filename)
{
int ret = EXIT_SUCCESS;
sexp ctx;
sexp scheme_ret;
sexp_scheme_init();
ctx = sexp_make_eval_context(NULL, NULL, NULL, 0, 0);
sexp_load_standard_env(ctx, NULL, SEXP_SEVEN);
sexp_load_standard_ports(ctx, NULL, stdin, stdout, stderr, 1);
sexp_gc_var1(filename_obj);
if (register_ftracetool_api(ctx) != 0)
{
fprintf(stderr, "Unable to register ftracetool API\n");
return EXIT_FAILURE;
}
filename_obj = sexp_c_string(ctx, filename, -1);
scheme_ret = sexp_load(ctx, filename_obj, NULL);
if (sexp_exceptionp(scheme_ret))
{
fprintf(stderr, "Exception occured while executing %s:\n", filename);
sexp_print_exception(ctx, scheme_ret, sexp_current_output_port(ctx));
ret = EXIT_FAILURE;
}
sexp_gc_release1(filename_obj);
sexp_destroy_context(ctx);
return ret;
}
int main(int argc, char **argv)
{
int opt = 0;
char filename[NAME_MAX] = {};
bool execute_script = false;
bool show_symbols_in_file = false;
while ((opt = getopt(argc, argv, "vhs:e:")) != -1)
{
switch (opt)
{
case 'v':
{
show_version();
return 0;
}
case 'h':
{
show_usage();
return 0;
}
case 'e':
{
strncpy(filename, optarg, NAME_MAX - 1);
execute_script = true;
break;
}
case 's':
{
strncpy(filename, optarg, NAME_MAX - 1);
show_symbols_in_file = true;
break;
}
default:
{
show_usage();
return EXIT_FAILURE;
}
}
}
if (execute_script && show_symbols_in_file)
{
fprintf(stderr, "-e and -s are mutually exclusive\n");
exit(EXIT_FAILURE);
}
if (show_symbols_in_file)
{
return do_show_symbols_in_file(filename);
}
else if (execute_script)
{
return do_execute_script(filename);
}
return 0;
}

6
src/version.h

@ -0,0 +1,6 @@
#ifndef VERSION_H
#define VERSION_H
#define VERSION_STRING "0.1"
#endif
Loading…
Cancel
Save