|
|
|
@ -120,14 +120,14 @@ unsigned long lookup_symbol_in_file(const char *const filename, |
|
|
|
if (fd == -1) |
|
|
|
if (fd == -1) |
|
|
|
{ |
|
|
|
{ |
|
|
|
perror("open() failed"); |
|
|
|
perror("open() failed"); |
|
|
|
return EXIT_FAILURE; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
(void)elf_version(EV_CURRENT); |
|
|
|
(void)elf_version(EV_CURRENT); |
|
|
|
|
|
|
|
|
|
|
|
if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) |
|
|
|
if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) |
|
|
|
{ |
|
|
|
{ |
|
|
|
fprintf(stderr, "elf_begin() failed: %s\n", elf_errmsg(elf_errno())); |
|
|
|
fprintf(stderr, "elf_begin() failed: %s\n", elf_errmsg(elf_errno())); |
|
|
|
return EXIT_FAILURE; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
while ((scn = elf_nextscn(elf, scn)) != NULL) |
|
|
|
while ((scn = elf_nextscn(elf, scn)) != NULL) |
|
|
|
@ -190,7 +190,7 @@ unsigned long lookup_symbol_in_file(const char *const filename, |
|
|
|
} |
|
|
|
} |
|
|
|
elf_end(elf); |
|
|
|
elf_end(elf); |
|
|
|
|
|
|
|
|
|
|
|
return -1; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int do_show_symbols_in_file(const char *const filename) |
|
|
|
static int do_show_symbols_in_file(const char *const filename) |
|
|
|
@ -289,7 +289,211 @@ static sexp sexp_lookup_symbol_in_file_stub( |
|
|
|
return res; |
|
|
|
return res; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int register_ftracetool_api(sexp ctx) |
|
|
|
static sexp display_exception(sexp ctx, sexp self, sexp_sint_t n, sexp arg0) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
sexp res; |
|
|
|
|
|
|
|
if (!sexp_exceptionp(arg0)) |
|
|
|
|
|
|
|
return sexp_type_exception(ctx, self, SEXP_EXCEPTION, arg0); |
|
|
|
|
|
|
|
sexp_print_exception(ctx, arg0, sexp_current_error_port(ctx)); |
|
|
|
|
|
|
|
return res; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static sexp sexp_sleep_stub(sexp ctx, sexp self, sexp_sint_t n, sexp arg0) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
sexp res; |
|
|
|
|
|
|
|
if (!sexp_numberp(arg0)) |
|
|
|
|
|
|
|
return sexp_type_exception(ctx, self, SEXP_NUMBER, arg0); |
|
|
|
|
|
|
|
sleep(sexp_uint_value(arg0)); |
|
|
|
|
|
|
|
return res; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int parse_ftrace_entry(const char *str, |
|
|
|
|
|
|
|
char *comm_buf, |
|
|
|
|
|
|
|
char *pid_buf, |
|
|
|
|
|
|
|
char *timestamp_buf, |
|
|
|
|
|
|
|
char *probe_id_buf, |
|
|
|
|
|
|
|
char *args_buf) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// skip whitespaces
|
|
|
|
|
|
|
|
while (isspace(*str)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
str++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!*str) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return -1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char *out = comm_buf; |
|
|
|
|
|
|
|
while (*str != '-') |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (!*str) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return -2; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// TODO check out buf overflow
|
|
|
|
|
|
|
|
*out++ = *str++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!*str) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return -3; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
*out = 0; |
|
|
|
|
|
|
|
str++; // Skip '-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
out = pid_buf; |
|
|
|
|
|
|
|
while (isdigit(*str)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (!*str) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return -4; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO check out buf overflow
|
|
|
|
|
|
|
|
*out++ = *str++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
*out = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// skip everything until ]
|
|
|
|
|
|
|
|
while (*str != ']') |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
str++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!*str) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return -5; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
str++; |
|
|
|
|
|
|
|
if (!*str) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return -6; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// skip whitespaces && flags
|
|
|
|
|
|
|
|
while (isspace(*str) || isalpha(*str)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
str++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!*str) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return -7; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
out = timestamp_buf; |
|
|
|
|
|
|
|
while (isdigit(*str) || *str == '.') |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (!*str) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return -8; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO check out buf overflow
|
|
|
|
|
|
|
|
*out++ = *str++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
*out = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (*str != ':') |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return -9; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
str++; |
|
|
|
|
|
|
|
// skip whitespaces
|
|
|
|
|
|
|
|
while (isspace(*str)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
str++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!*str) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return -10; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
out = probe_id_buf; |
|
|
|
|
|
|
|
while (isalnum(*str) || *str == '_') |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (!*str) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return -11; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// TODO check out buf overflow
|
|
|
|
|
|
|
|
*out++ = *str++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
*out = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// skip everything until )
|
|
|
|
|
|
|
|
while (*str != ')') |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
str++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!*str) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return -12; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
str++; |
|
|
|
|
|
|
|
if (!*str) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return -13; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
out = args_buf; |
|
|
|
|
|
|
|
while (*str) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (!*str) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return -14; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// TODO check out buf overflow
|
|
|
|
|
|
|
|
*out++ = *str++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
*out = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static sexp |
|
|
|
|
|
|
|
sexp_parse_ftrace_entry_stub(sexp ctx, sexp self, sexp_sint_t n, sexp arg0) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
sexp res; |
|
|
|
|
|
|
|
int ret = 0; |
|
|
|
|
|
|
|
if (!sexp_stringp(arg0)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return sexp_type_exception(ctx, self, SEXP_STRING, arg0); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
char comm_buf[128]; |
|
|
|
|
|
|
|
char pid_buf[32]; |
|
|
|
|
|
|
|
char timestamp_buf[64]; |
|
|
|
|
|
|
|
char probe_id_buf[64]; |
|
|
|
|
|
|
|
char args[128]; |
|
|
|
|
|
|
|
ret = parse_ftrace_entry(sexp_string_data(arg0), |
|
|
|
|
|
|
|
comm_buf, |
|
|
|
|
|
|
|
pid_buf, |
|
|
|
|
|
|
|
timestamp_buf, |
|
|
|
|
|
|
|
probe_id_buf, |
|
|
|
|
|
|
|
args); |
|
|
|
|
|
|
|
if (ret) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return SEXP_FALSE; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
unsigned long pid = atoi(pid_buf); |
|
|
|
|
|
|
|
char *dot = strchr(timestamp_buf, '.'); |
|
|
|
|
|
|
|
*dot = 0; |
|
|
|
|
|
|
|
char *frac = dot + 1; |
|
|
|
|
|
|
|
double timestamp = atol(timestamp_buf) + atol(frac) / 1000000.; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return sexp_cons( |
|
|
|
|
|
|
|
ctx, |
|
|
|
|
|
|
|
sexp_c_string(ctx, comm_buf, -1), |
|
|
|
|
|
|
|
sexp_cons(ctx, |
|
|
|
|
|
|
|
sexp_make_fixnum(pid), |
|
|
|
|
|
|
|
sexp_cons(ctx, |
|
|
|
|
|
|
|
sexp_make_flonum(ctx, timestamp), |
|
|
|
|
|
|
|
sexp_cons(ctx, |
|
|
|
|
|
|
|
sexp_c_string(ctx, probe_id_buf, -1), |
|
|
|
|
|
|
|
sexp_cons(ctx, |
|
|
|
|
|
|
|
sexp_c_string(ctx, args, -1), |
|
|
|
|
|
|
|
SEXP_NULL))))); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int register_lookup_symbol_in_file(sexp ctx) |
|
|
|
{ |
|
|
|
{ |
|
|
|
sexp_gc_var1(op); |
|
|
|
sexp_gc_var1(op); |
|
|
|
sexp_gc_preserve1(ctx, op); |
|
|
|
sexp_gc_preserve1(ctx, op); |
|
|
|
@ -309,6 +513,106 @@ static int register_ftracetool_api(sexp ctx) |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int register_display_exception(sexp ctx) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
sexp_gc_var1(op); |
|
|
|
|
|
|
|
sexp_gc_preserve1(ctx, op); |
|
|
|
|
|
|
|
op = sexp_define_foreign( |
|
|
|
|
|
|
|
ctx, sexp_context_env(ctx), "display-exception", 1, display_exception); |
|
|
|
|
|
|
|
if (sexp_opcodep(op)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
sexp_opcode_return_type(op) = sexp_make_fixnum(SEXP_NULL); |
|
|
|
|
|
|
|
sexp_opcode_arg1_type(op) = sexp_make_fixnum(SEXP_EXCEPTION); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
sexp_gc_release1(ctx); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int register_sleep(sexp ctx) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
sexp_gc_var1(op); |
|
|
|
|
|
|
|
sexp_gc_preserve1(ctx, op); |
|
|
|
|
|
|
|
op = sexp_define_foreign( |
|
|
|
|
|
|
|
ctx, sexp_context_env(ctx), "sleep", 1, sexp_sleep_stub); |
|
|
|
|
|
|
|
if (sexp_opcodep(op)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
sexp_opcode_return_type(op) = sexp_make_fixnum(SEXP_NULL); |
|
|
|
|
|
|
|
sexp_opcode_arg1_type(op) = sexp_make_fixnum(SEXP_NUMBER); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
sexp_gc_release1(ctx); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sexp sexp_open_append_file_op(sexp ctx, sexp self, sexp_sint_t n, sexp path) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
FILE *out; |
|
|
|
|
|
|
|
int count = 0; |
|
|
|
|
|
|
|
sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, path); |
|
|
|
|
|
|
|
do |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (count != 0) |
|
|
|
|
|
|
|
sexp_gc(ctx, NULL); |
|
|
|
|
|
|
|
out = fopen(sexp_string_data(path), "a+"); |
|
|
|
|
|
|
|
} while (!out && sexp_out_of_file_descriptors() && !count++); |
|
|
|
|
|
|
|
if (!out) |
|
|
|
|
|
|
|
return sexp_file_exception( |
|
|
|
|
|
|
|
ctx, self, "couldn't open output file", path); |
|
|
|
|
|
|
|
#if SEXP_USE_GREEN_THREADS |
|
|
|
|
|
|
|
fcntl(fileno(out), F_SETFL, O_NONBLOCK); |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
return sexp_make_output_port(ctx, out, path); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int register_open_append_file(sexp ctx) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
sexp_gc_var1(op); |
|
|
|
|
|
|
|
sexp_gc_preserve1(ctx, op); |
|
|
|
|
|
|
|
op = sexp_define_foreign(ctx, |
|
|
|
|
|
|
|
sexp_context_env(ctx), |
|
|
|
|
|
|
|
"open-append-file", |
|
|
|
|
|
|
|
1, |
|
|
|
|
|
|
|
sexp_open_append_file_op); |
|
|
|
|
|
|
|
if (sexp_opcodep(op)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
sexp_opcode_return_type(op) = sexp_make_fixnum(SEXP_OPORT); |
|
|
|
|
|
|
|
sexp_opcode_arg1_type(op) = sexp_make_fixnum(SEXP_NUMBER); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
sexp_gc_release1(ctx); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int register_parse_ftrace_entry(sexp ctx) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
sexp_gc_var1(op); |
|
|
|
|
|
|
|
sexp_gc_preserve1(ctx, op); |
|
|
|
|
|
|
|
op = sexp_define_foreign(ctx, |
|
|
|
|
|
|
|
sexp_context_env(ctx), |
|
|
|
|
|
|
|
"parse-ftrace-entry", |
|
|
|
|
|
|
|
1, |
|
|
|
|
|
|
|
sexp_parse_ftrace_entry_stub); |
|
|
|
|
|
|
|
if (sexp_opcodep(op)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
sexp_opcode_return_type(op) = sexp_make_fixnum(SEXP_PAIR); |
|
|
|
|
|
|
|
sexp_opcode_arg1_type(op) = sexp_make_fixnum(SEXP_STRING); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
sexp_gc_release1(ctx); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int register_ftracetool_api(sexp ctx) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
register_lookup_symbol_in_file(ctx); |
|
|
|
|
|
|
|
register_display_exception(ctx); |
|
|
|
|
|
|
|
register_sleep(ctx); |
|
|
|
|
|
|
|
register_open_append_file(ctx); |
|
|
|
|
|
|
|
register_parse_ftrace_entry(ctx); |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int eval_ftracetool_scm(sexp ctx) |
|
|
|
static int eval_ftracetool_scm(sexp ctx) |
|
|
|
{ |
|
|
|
{ |
|
|
|
sexp_gc_var2(ret, fname); |
|
|
|
sexp_gc_var2(ret, fname); |
|
|
|
|