diff --git a/src/ftracetool.c b/src/ftracetool.c index ba3c643..d91bdfe 100644 --- a/src/ftracetool.c +++ b/src/ftracetool.c @@ -34,6 +34,8 @@ struct ftt_mapping struct ftt_mapping *next; }; +static int g_max_lines = 0; + static struct ftt_mapping *gs_mappings; static struct ftt_mapping *parse_mapping(const char *const raw_str) @@ -92,6 +94,16 @@ static int embed_mappings(sexp ctx) sexp_gc_release2(ctx); } +static int embed_options(sexp ctx) +{ + sexp_gc_var2(option_name, option_value); + sexp_gc_preserve2(ctx, option_name, option_value); + option_name = sexp_intern(ctx, "*max-lines*", -1); + option_value = sexp_make_fixnum(g_max_lines); + sexp_env_define(ctx, sexp_context_env(ctx), option_name, option_value); + sexp_gc_release2(ctx); +} + static void show_version() { printf("ftracetool v%s\n", VERSION_STRING); @@ -321,22 +333,13 @@ static int parse_ftrace_entry(const char *str, char **args, size_t *args_num) { - // skip whitespaces - while (isspace(*str)) - { - str++; - } - if (!*str) - { - return ER_PARSE_ERROR + 1; - } if (*str == '#') { return ER_COMMENT; } char *out = comm_buf; - while (*str != '-') + for (size_t i = 0; i < 16; i++) { if (!*str) { @@ -381,7 +384,7 @@ static int parse_ftrace_entry(const char *str, } // skip whitespaces && flags - while (isspace(*str) || isalpha(*str)) + while (isspace(*str) || isalpha(*str) || *str == '.') { str++; } @@ -512,25 +515,23 @@ sexp_parse_ftrace_entry_stub(sexp ctx, sexp self, sexp_sint_t n, sexp arg0) char *frac = dot + 1; double timestamp = atol(timestamp_buf) + atol(frac) / 1000000.; - sexp prev = SEXP_NULL; - sexp head = SEXP_NULL; + sexp_gc_var5(prev, head, res, tmp, data); + sexp_gc_preserve5(ctx, prev, head, res, tmp, data); for (ssize_t arg_num = args_num - 1; arg_num >= 0; arg_num--) { head = sexp_cons(ctx, sexp_c_string(ctx, args[arg_num], -1), prev); prev = head; free(args[arg_num]); } + tmp = sexp_cons(ctx, head, SEXP_NULL); + tmp = sexp_cons(ctx, data = sexp_c_string(ctx, probe_id_buf, -1), tmp); + tmp = sexp_cons(ctx, data = sexp_make_flonum(ctx, timestamp), tmp); + tmp = sexp_cons(ctx, data = sexp_make_fixnum(pid), tmp); + tmp = sexp_cons(ctx, data = sexp_c_string(ctx, comm_buf, -1), tmp); - 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, head, SEXP_NULL))))); + res = tmp; + sexp_gc_release5(ctx); + return res; } static int register_lookup_symbol_in_file(sexp ctx) @@ -680,6 +681,7 @@ static int do_execute_script(const char *const filename) sexp_load_standard_env(ctx, NULL, SEXP_SEVEN); sexp_load_standard_ports(ctx, NULL, stdin, stdout, stderr, 1); embed_mappings(ctx); + embed_options(ctx); sexp_gc_var1(filename_obj); @@ -743,6 +745,11 @@ int main(int argc, char **argv) show_symbols_in_file = true; break; } + case 'l': + { + g_max_lines = atoi(optarg); + break; + } case 'm': { struct ftt_mapping *const mapping = parse_mapping(optarg); diff --git a/src/ftracetool.scm b/src/ftracetool.scm index a5f0d12..b73e76e 100644 --- a/src/ftracetool.scm +++ b/src/ftracetool.scm @@ -9,12 +9,13 @@ (let ((pair (assoc key *ftt-mappings*))) (if pair (cdr pair) - (raise (string-append "No mapping: " key))))) + #f))) (define (mapping-int key) (let ((value (mapping-str key))) - (when value - (string->number value)))) + (if value + (string->number value) + #f))) (define (with-append-to-file file thunk) (let ((old-out (current-output-port)) @@ -204,64 +205,44 @@ (string-cursor-next x (string-index x #\=)) (string-cursor-end x))) raw-args))) -(define (read-trace-events-from-file filename) - (let ((rx (regexp '(: - (+ whitespace) - ($ alnum (+ (~ "-"))) - "-" - ($ word) - (+ whitespace) - "[" - (+ num) - "]" - (+ whitespace) - (+ (~ whitespace)) - (+ whitespace) - ($ (+ (or num "."))) - ":" - (+ whitespace) - ($ (+ (or alnum "_"))) - ": (" - (+ (~ ")")) - ")" - ($ (+ any)) - )))) - (reverse - (call-with-input-file filename - (lambda (p) - (let loop ((line (read-line p)) - (events '()) - (n 0)) - (if (or (eof-object? line) - (> n 1000)) - events - (begin - (let ((match (parse-ftrace-entry line))) - (if match - (let* ((comm (list-ref match 0)) - (pid (list-ref match 1)) - (timestamp (list-ref match 2)) - (probe-name (list-ref match 3)) - (args (list-ref match 4)) - (trace-event (make-trace-event timestamp probe-name pid args))) - (loop (read-line p) (cons trace-event events) (+ 1 n))) - (loop (read-line p) events n))))))))))) +(define (read-trace-events-from-file filename max-lines) + (reverse + (call-with-input-file filename + (lambda (p) + (let loop ((line (read-line p)) + (events '()) + (n 0)) + (if (or (eof-object? line) + (if max-lines (> n max-lines) #f)) + events + (begin + (let ((match (parse-ftrace-entry line))) + (if match + (begin + (let* ((comm (list-ref match 0)) + (pid (list-ref match 1)) + (timestamp (list-ref match 2)) + (probe-name (list-ref match 3)) + (args (list-ref match 4)) + (trace-event (make-trace-event timestamp probe-name pid args))) + (loop (read-line p) (cons trace-event events) (+ 1 n)))) + (loop (read-line p) events n)))))))))) (define (find-subprobe probe-name subprobes) (find (lambda (x) (equal? probe-name (ftrace-probe-name x))) subprobes)) (define (ftrace-process subprobes) + (let ((max-lines (if (> *max-lines* 0) *max-lines* #f))) (with-output-to-file "/sys/kernel/tracing/events/uprobes/enable" (lambda () (display "0") (newline))) - (let ((events (read-trace-events-from-file "/sys/kernel/tracing/trace"))) + (let ((events (read-trace-events-from-file "/sys/kernel/tracing/trace" max-lines))) (for-each (lambda (event) (let ((probe (find-subprobe (trace-event-probe-id event) subprobes))) (when probe - ((ftrace-probe-process-entry-handler probe) event))) - ) events))) + ((ftrace-probe-process-entry-handler probe) event)))) events)))) (define (tracing-probe ctx install remove process) (make-probe (lambda () (install ctx))