-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tools: bpftool: add a command to dump the trace pipe
BPF programs can use the bpf_trace_printk() helper to print debug information into the trace pipe. Add a subcommand "bpftool prog tracelog" to simply dump this pipe to the console. This is for a good part copied from iproute2, where the feature is available with "tc exec bpf dbg". Changes include dumping pipe content to stdout instead of stderr and adding JSON support (content is dumped as an array of strings, one per line read from the pipe). This version is dual-licensed, with Daniel's permission. Cc: Daniel Borkmann <daniel@iogearbox.net> Suggested-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
- Loading branch information
Quentin Monnet
authored and
Daniel Borkmann
committed
Dec 5, 2018
1 parent
4188817
commit 30da46b
Showing
5 changed files
with
176 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
/* Copyright (c) 2015-2017 Daniel Borkmann */ | ||
/* Copyright (c) 2018 Netronome Systems, Inc. */ | ||
|
||
#include <errno.h> | ||
#include <limits.h> | ||
#include <signal.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <unistd.h> | ||
#include <linux/magic.h> | ||
#include <sys/fcntl.h> | ||
#include <sys/vfs.h> | ||
|
||
#include "main.h" | ||
|
||
#ifndef TRACEFS_MAGIC | ||
# define TRACEFS_MAGIC 0x74726163 | ||
#endif | ||
|
||
#define _textify(x) #x | ||
#define textify(x) _textify(x) | ||
|
||
FILE *trace_pipe_fd; | ||
char *buff; | ||
|
||
static int validate_tracefs_mnt(const char *mnt, unsigned long magic) | ||
{ | ||
struct statfs st_fs; | ||
|
||
if (statfs(mnt, &st_fs) < 0) | ||
return -ENOENT; | ||
if ((unsigned long)st_fs.f_type != magic) | ||
return -ENOENT; | ||
|
||
return 0; | ||
} | ||
|
||
static bool | ||
find_tracefs_mnt_single(unsigned long magic, char *mnt, const char *mntpt) | ||
{ | ||
size_t src_len; | ||
|
||
if (validate_tracefs_mnt(mntpt, magic)) | ||
return false; | ||
|
||
src_len = strlen(mntpt); | ||
if (src_len + 1 >= PATH_MAX) { | ||
p_err("tracefs mount point name too long"); | ||
return false; | ||
} | ||
|
||
strcpy(mnt, mntpt); | ||
return true; | ||
} | ||
|
||
static bool find_tracefs_pipe(char *mnt) | ||
{ | ||
static const char * const known_mnts[] = { | ||
"/sys/kernel/debug/tracing", | ||
"/sys/kernel/tracing", | ||
"/tracing", | ||
"/trace", | ||
}; | ||
const char *pipe_name = "/trace_pipe"; | ||
const char *fstype = "tracefs"; | ||
char type[100], format[32]; | ||
const char * const *ptr; | ||
bool found = false; | ||
FILE *fp; | ||
|
||
for (ptr = known_mnts; ptr < known_mnts + ARRAY_SIZE(known_mnts); ptr++) | ||
if (find_tracefs_mnt_single(TRACEFS_MAGIC, mnt, *ptr)) | ||
goto exit_found; | ||
|
||
fp = fopen("/proc/mounts", "r"); | ||
if (!fp) | ||
return false; | ||
|
||
/* Allow room for NULL terminating byte and pipe file name */ | ||
snprintf(format, sizeof(format), "%%*s %%%zds %%99s %%*s %%*d %%*d\\n", | ||
PATH_MAX - strlen(pipe_name) - 1); | ||
while (fscanf(fp, format, mnt, type) == 2) | ||
if (strcmp(type, fstype) == 0) { | ||
found = true; | ||
break; | ||
} | ||
fclose(fp); | ||
|
||
/* The string from fscanf() might be truncated, check mnt is valid */ | ||
if (!found || validate_tracefs_mnt(mnt, TRACEFS_MAGIC)) | ||
return false; | ||
|
||
exit_found: | ||
strcat(mnt, pipe_name); | ||
return true; | ||
} | ||
|
||
static void exit_tracelog(int signum) | ||
{ | ||
fclose(trace_pipe_fd); | ||
free(buff); | ||
|
||
if (json_output) { | ||
jsonw_end_array(json_wtr); | ||
jsonw_destroy(&json_wtr); | ||
} | ||
|
||
exit(0); | ||
} | ||
|
||
int do_tracelog(int argc, char **argv) | ||
{ | ||
const struct sigaction act = { | ||
.sa_handler = exit_tracelog | ||
}; | ||
char trace_pipe[PATH_MAX]; | ||
bool found_trace_pipe; | ||
size_t buff_len = 0; | ||
|
||
if (json_output) | ||
jsonw_start_array(json_wtr); | ||
|
||
found_trace_pipe = find_tracefs_pipe(trace_pipe); | ||
if (!found_trace_pipe) { | ||
p_err("could not find trace pipe, tracefs not mounted?"); | ||
return -1; | ||
} | ||
|
||
trace_pipe_fd = fopen(trace_pipe, "r"); | ||
if (!trace_pipe_fd) { | ||
p_err("could not open trace pipe: %s", strerror(errno)); | ||
return -1; | ||
} | ||
|
||
sigaction(SIGHUP, &act, NULL); | ||
sigaction(SIGINT, &act, NULL); | ||
sigaction(SIGTERM, &act, NULL); | ||
while (1) { | ||
ssize_t ret; | ||
|
||
ret = getline(&buff, &buff_len, trace_pipe_fd); | ||
if (ret <= 0) { | ||
p_err("failed to read content from trace pipe: %s", | ||
strerror(errno)); | ||
break; | ||
} | ||
if (json_output) | ||
jsonw_string(json_wtr, buff); | ||
else | ||
printf("%s", buff); | ||
} | ||
|
||
fclose(trace_pipe_fd); | ||
free(buff); | ||
return -1; | ||
} |