Skip to content

Commit

Permalink
Enable printf, cat, system to have more args
Browse files Browse the repository at this point in the history
  • Loading branch information
suyuee committed Jun 30, 2020
1 parent 7175447 commit bb2e5d4
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 42 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ and this project adheres to
- [#1377](https://github.com/iovisor/bpftrace/pull/1377)
- Add support for non-map print()
- [#1381](https://github.com/iovisor/bpftrace/pull/1381)
- Enable `printf`, `cat` and `system` to have more than 7 arguments
- [#1404](https://github.com/iovisor/bpftrace/pull/1404)

#### Changed

Expand Down
2 changes: 1 addition & 1 deletion src/ast/semantic_analyser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@ void SemanticAnalyser::visit(Call &call)
else if (call.func == "printf" || call.func == "system" || call.func == "cat")
{
check_assignment(call, false, false, false);
if (check_varargs(call, 1, 7))
if (check_varargs(call, 1, std::numeric_limits<int>::max()))
{
check_arg(call, Type::string, 0, true);
if (is_final_pass())
Expand Down
76 changes: 35 additions & 41 deletions src/bpftrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,52 +49,46 @@ DebugLevel bt_debug = DebugLevel::kNone;
bool bt_verbose = false;
volatile sig_atomic_t BPFtrace::exitsig_recv = false;

int format(char * s, size_t n, const char * fmt, std::vector<std::unique_ptr<IPrintable>> &args) {
int format(char *s,
size_t n,
std::string fmt,
std::vector<std::unique_ptr<IPrintable>> &args)
{
// Args have been made safe for printing by now, so replace nonstandard format
// specifiers with %s
std::string str = std::string(fmt);
size_t start_pos = 0;
while ((start_pos = str.find("%r", start_pos)) != std::string::npos)
while ((start_pos = fmt.find("%r", start_pos)) != std::string::npos)
{
str.replace(start_pos, 2, "%s");
fmt.replace(start_pos, 2, "%s");
start_pos += 2;
}
fmt = str.c_str();

int ret = -1;
switch(args.size()) {
case 0:
ret = snprintf(s, n, "%s", fmt);
break;
case 1:
ret = snprintf(s, n, fmt, args.at(0)->value());
break;
case 2:
ret = snprintf(s, n, fmt, args.at(0)->value(), args.at(1)->value());
break;
case 3:
ret = snprintf(s, n, fmt, args.at(0)->value(), args.at(1)->value(), args.at(2)->value());
break;
case 4:
ret = snprintf(s, n, fmt, args.at(0)->value(), args.at(1)->value(), args.at(2)->value(), args.at(3)->value());
break;
case 5:
ret = snprintf(s, n, fmt, args.at(0)->value(), args.at(1)->value(), args.at(2)->value(),
args.at(3)->value(), args.at(4)->value());
break;
case 6:
ret = snprintf(s, n, fmt, args.at(0)->value(), args.at(1)->value(), args.at(2)->value(),
args.at(3)->value(), args.at(4)->value(), args.at(5)->value());
break;
default:
std::cerr << "format() can only take up to 7 arguments (" << args.size() << ") provided" << std::endl;
const std::regex re("%-?[0-9]*(\\.[0-9]+)?[a-zA-Z]+");
auto tokens_begin = std::sregex_iterator(fmt.begin(), fmt.end(), re);
auto tokens_end = std::sregex_iterator();

int text_pos = 0;
int i = 0;
std::string str;
while (tokens_begin != tokens_end)
{
int match_start = tokens_begin->position();
str += fmt.substr(text_pos, match_start - text_pos);
int r = snprintf(s, n, tokens_begin->str().c_str(), args.at(i)->value());
if (r < 0)
{
std::cerr << "format() error occurred: " << std::strerror(errno)
<< std::endl;
abort();
}
if (ret < 0 && errno != 0) {
std::cerr << "format() error occurred: " << std::strerror(errno) << std::endl;
abort();
}
return ret;
}
str += std::string(s);
text_pos = tokens_begin->position() + tokens_begin->length();
++tokens_begin;
++i;
}
str += fmt.substr(text_pos);
strncpy(s, str.c_str(), n);
return str.length();
}

BPFtrace::~BPFtrace()
Expand Down Expand Up @@ -573,7 +567,7 @@ void perf_event_printer(void *cb_cookie, void *data, int size __attribute__((unu
}

auto id = printf_id - asyncactionint(AsyncAction::syscall);
auto fmt = std::get<0>(bpftrace->system_args_[id]).c_str();
auto fmt = std::get<0>(bpftrace->system_args_[id]);
auto args = std::get<1>(bpftrace->system_args_[id]);
auto arg_values = bpftrace->get_arg_values(args, arg_data);

Expand All @@ -593,7 +587,7 @@ void perf_event_printer(void *cb_cookie, void *data, int size __attribute__((unu
else if ( printf_id >= asyncactionint(AsyncAction::cat))
{
auto id = printf_id - asyncactionint(AsyncAction::cat);
auto fmt = std::get<0>(bpftrace->cat_args_[id]).c_str();
auto fmt = std::get<0>(bpftrace->cat_args_[id]);
auto args = std::get<1>(bpftrace->cat_args_[id]);
auto arg_values = bpftrace->get_arg_values(args, arg_data);

Expand All @@ -615,7 +609,7 @@ void perf_event_printer(void *cb_cookie, void *data, int size __attribute__((unu
}

// printf
auto fmt = std::get<0>(bpftrace->printf_args_[printf_id]).c_str();
auto fmt = std::get<0>(bpftrace->printf_args_[printf_id]);
auto args = std::get<1>(bpftrace->printf_args_[printf_id]);
auto arg_values = bpftrace->get_arg_values(args, arg_data);

Expand Down
15 changes: 15 additions & 0 deletions tests/runtime/call
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ RUN bpftrace -v -e 'struct Foo { int a; char b[10]; } uprobe:testprogs/uprobe_te
EXPECT 123 hello 456 world
TIMEOUT 5

NAME printf_more_arguments
RUN bpftrace -v -e 'BEGIN { printf("%d: %s; %d: %s;; %d: %s;;; %d: %s;;;;\\n", 1, "a", 2, "ab", 3, "abc", 4, "abcd"); exit(); }'
EXPECT 1: a; 2: ab;; 3: abc;;; 4: abcd;;;;
TIMEOUT 5

NAME time
RUN bpftrace -v -e 'i:ms:1 { time("%H:%M:%S\n"); exit();}'
EXPECT [0-9]*:[0-9]*:[0-9]*
Expand Down Expand Up @@ -87,6 +92,11 @@ RUN bpftrace --unsafe -v -e 'i:ms:100 { system("echo 'ok_system'"); exit();}'
EXPECT ok_system
TIMEOUT 5

NAME system_more_args
RUN bpftrace --unsafe -v -e 'i:ms:100 { system("echo %d %d %d %d %d %d %d", 1, 2, 3, 4, 5, 6, 7); exit();}'
EXPECT 1 2 3 4 5 6 7
TIMEOUT 5

NAME count
RUN bpftrace -v -e 'i:ms:100 { @ = count(); exit();}'
EXPECT @:\s[0-9]+
Expand Down Expand Up @@ -151,6 +161,11 @@ RUN bpftrace -v -e 'i:ms:1 { cat("/proc/uptime"); exit();}'
EXPECT [0-9]*.[0-9]* [0-9]*.[0-9]*
TIMEOUT 5

NAME cat_more_args
RUN bpftrace -v -e 'i:ms:1 { cat("/%s%s%s%s/%s%s%s", "p", "r", "o", "c", "u", "p", "time"); exit();}'
EXPECT [0-9]*.[0-9]* [0-9]*.[0-9]*
TIMEOUT 5

NAME uaddr
RUN bpftrace -v -e 'uprobe:testprogs/uprobe_test:function1 { printf("0x%lx -- 0x%lx\n", *uaddr("GLOBAL_A"), *uaddr("GLOBAL_C")); exit(); }' -c ./testprogs/uprobe_test
EXPECT 0x55555555 -- 0x33333333
Expand Down
3 changes: 3 additions & 0 deletions tests/semantic_analyser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,9 @@ TEST(semantic_analyser, printf)
test("kprobe:f { printf(\"%A\", comm) }", 10);
test("kprobe:f { @x = printf(\"hi\") }", 1);
test("kprobe:f { $x = printf(\"hi\") }", 1);
test("kprobe:f { printf(\"%d %d %d %d %d %d %d %d %d\", 1, 2, 3, 4, 5, 6, 7, "
"8, 9); }",
0);
}

TEST(semantic_analyser, system)
Expand Down

0 comments on commit bb2e5d4

Please sign in to comment.