Commit 7d490e54 authored by williangaspar's avatar williangaspar
parent 7404d0e8
......@@ -430,6 +430,55 @@ void CodegenLLVM::visit(Call &call)
b_.CreateLifetimeEnd(printf_args);
expr_ = nullptr;
}
else if (call.func == "system")
{
/*
* perf event output has: uint64_t system_id, vargs
* The system_id maps to bpftrace_.system_args_, and is a way to define the
* types and offsets of each of the arguments, and share that between BPF and
* user-space for printing.
*/
ArrayType *string_type = ArrayType::get(b_.getInt8Ty(), STRING_SIZE);
std::vector<llvm::Type *> elements = { b_.getInt64Ty() }; // system ID
String &fmt = static_cast<String&>(*call.vargs->at(0));
auto &args = std::get<1>(bpftrace_.system_args_.at(system_id_));
for (Field &arg : args)
{
llvm::Type *ty = b_.GetType(arg.type);
elements.push_back(ty);
}
StructType *printf_struct = StructType::create(elements, "system_t", false);
int struct_size = layout_.getTypeAllocSize(printf_struct);
auto *struct_layout = layout_.getStructLayout(printf_struct);
for (int i=0; i<args.size(); i++)
{
Field &arg = args[i];
arg.offset = struct_layout->getElementOffset(i+1); // +1 for the system_id field
}
AllocaInst *system_args = b_.CreateAllocaBPF(printf_struct, "system_args");
b_.CreateMemSet(system_args, b_.getInt8(0), struct_size, 1);
b_.CreateStore(b_.getInt64(system_id_ + 10000), system_args);
for (int i=1; i<call.vargs->size(); i++)
{
Expression &arg = *call.vargs->at(i);
arg.accept(*this);
Value *offset = b_.CreateGEP(system_args, {b_.getInt32(0), b_.getInt32(i)});
if (arg.type.type == Type::string || arg.type.type == Type::usym)
b_.CreateMemCpy(offset, expr_, arg.type.size, 1);
else
b_.CreateStore(expr_, offset);
// b_.CreateStore(b_.getInt64(asyncactionint(AsyncAction::exit)), perfdata);
}
system_id_++;
b_.CreatePerfEventOutput(ctx_, system_args, struct_size);
b_.CreateLifetimeEnd(system_args);
expr_ = nullptr;
}
else if (call.func == "exit")
{
/*
......
......@@ -71,6 +71,7 @@ private:
std::map<std::string, Value *> variables_;
int printf_id_ = 0;
int time_id_ = 0;
int system_id_ = 0;
};
} // namespace ast
......
......@@ -232,7 +232,7 @@ void SemanticAnalyser::visit(Call &call)
}
call.type = SizedType(Type::integer, 8);
}
else if (call.func == "printf") {
else if (call.func == "printf" || call.func == "system") {
check_assignment(call, false, false);
if (check_varargs(call, 1, 7)) {
check_arg(call, Type::string, 0, true);
......@@ -245,7 +245,10 @@ void SemanticAnalyser::visit(Call &call)
}
err_ << verify_format_string(fmt.str, args);
if (call.func == "printf")
bpftrace_.printf_args_.push_back(std::make_tuple(fmt.str, args));
else
bpftrace_.system_args_.push_back(std::make_tuple(fmt.str, args));
}
}
......
......@@ -206,10 +206,132 @@ void perf_event_printer(void *cb_cookie, void *data, int size)
printf("\n");
return;
}
else if ( printf_id >= asyncactionint(AsyncAction::syscall))
{
auto id = printf_id - asyncactionint(AsyncAction::syscall);
auto fmt = std::get<0>(bpftrace->system_args_[id]).c_str();
auto args = std::get<1>(bpftrace->system_args_[id]);
std::vector<uint64_t> arg_values = bpftrace->get_arg_values(args, arg_data);
std::string command = "";
switch (args.size())
{
case 0:
system(fmt);
break;
case 1:
command = bpftrace->format_string(fmt, arg_values.at(0));
system(command.c_str());
break;
case 2:
command = bpftrace->format_string(fmt, arg_values.at(0), arg_values.at(1));
system(command.c_str());
break;
case 3:
command = bpftrace->format_string(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2));
system(command.c_str());
break;
case 4:
command = bpftrace->format_string(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2),
arg_values.at(3));
system(command.c_str());
break;
case 5:
command = bpftrace->format_string(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2),
arg_values.at(3), arg_values.at(4));
system(command.c_str());
break;
case 6:
command = bpftrace->format_string(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2),
arg_values.at(3), arg_values.at(4), arg_values.at(5));
system(command.c_str());
break;
default:
abort();
}
return;
}
// printf
auto fmt = std::get<0>(bpftrace->printf_args_[printf_id]).c_str();
auto args = std::get<1>(bpftrace->printf_args_[printf_id]);
std::vector<uint64_t> arg_values = bpftrace->get_arg_values(args, arg_data);
switch (args.size())
{
case 0:
printf(fmt);
break;
case 1:
printf(fmt, arg_values.at(0));
break;
case 2:
printf(fmt, arg_values.at(0), arg_values.at(1));
break;
case 3:
printf(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2));
break;
case 4:
printf(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2),
arg_values.at(3));
break;
case 5:
printf(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2),
arg_values.at(3), arg_values.at(4));
break;
case 6:
printf(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2),
arg_values.at(3), arg_values.at(4), arg_values.at(5));
break;
default:
abort();
}
}
void BPFtrace::format_impl(std::stringstream &ss, const char *format)
{
while (*format)
{
if (*format == '%' && *++format != '%') // %% == % (not a format directive)
throw std::invalid_argument("not enough arguments !\n");
ss << *format++;
}
}
template <typename Arg, typename... Args>
void BPFtrace::format_impl(std::stringstream &ss, const char *format, Arg arg, Args... args)
{
while (*format)
{
if (*format == '%' && *++format != '%')
{
auto current_format_qualifier = *format;
switch (current_format_qualifier)
{
case 'd':
if (!std::is_integral<Arg>())
throw std::invalid_argument("%d introduces integral argument");
}
ss << arg; // arg type is deduced
return format_impl(ss, ++format, args...); // one arg less
}
ss << *format++;
} // the format string is exhausted and we still have args : throw
throw std::invalid_argument("Too many arguments\n");
}
template <typename... Args>
std::string BPFtrace::format_string(const char *fmt, Args... args)
{
std::stringstream ss;
format_impl(ss, fmt, args...);
return ss.str();
}
std::vector<uint64_t> BPFtrace::get_arg_values(std::vector<Field> args, uint8_t* arg_data)
{
std::vector<uint64_t> arg_values;
std::vector<std::unique_ptr<char>> resolved_symbols;
std::vector<std::unique_ptr<char>> resolved_usernames;
......@@ -243,21 +365,21 @@ void perf_event_printer(void *cb_cookie, void *data, int size)
break;
case Type::sym:
resolved_symbols.emplace_back(strdup(
bpftrace->resolve_sym(*(uint64_t*)(arg_data+arg.offset)).c_str()));
resolve_sym(*(uint64_t*)(arg_data+arg.offset)).c_str()));
arg_values.push_back((uint64_t)resolved_symbols.back().get());
break;
case Type::usym:
resolved_symbols.emplace_back(strdup(
bpftrace->resolve_usym(*(uint64_t*)(arg_data+arg.offset), *(uint64_t*)(arg_data+arg.offset + 8)).c_str()));
resolve_usym(*(uint64_t*)(arg_data+arg.offset), *(uint64_t*)(arg_data+arg.offset + 8)).c_str()));
arg_values.push_back((uint64_t)resolved_symbols.back().get());
break;
case Type::username:
resolved_usernames.emplace_back(strdup(
bpftrace->resolve_uid(*(uint64_t*)(arg_data+arg.offset)).c_str()));
resolve_uid(*(uint64_t*)(arg_data+arg.offset)).c_str()));
arg_values.push_back((uint64_t)resolved_usernames.back().get());
break;
case Type::name:
name = strdup(bpftrace->resolve_name(*(uint64_t*)(arg_data+arg.offset)).c_str());
name = strdup(resolve_name(*(uint64_t*)(arg_data+arg.offset)).c_str());
arg_values.push_back((uint64_t)name);
break;
default:
......@@ -265,35 +387,7 @@ void perf_event_printer(void *cb_cookie, void *data, int size)
}
}
switch (args.size())
{
case 0:
printf(fmt);
break;
case 1:
printf(fmt, arg_values.at(0));
break;
case 2:
printf(fmt, arg_values.at(0), arg_values.at(1));
break;
case 3:
printf(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2));
break;
case 4:
printf(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2),
arg_values.at(3));
break;
case 5:
printf(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2),
arg_values.at(3), arg_values.at(4));
break;
case 6:
printf(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2),
arg_values.at(3), arg_values.at(4), arg_values.at(5));
break;
default:
abort();
}
return arg_values;
}
void perf_event_lost(void *cb_cookie, uint64_t lost)
......
......@@ -41,11 +41,24 @@ public:
uint64_t resolve_kname(const char *name);
uint64_t resolve_uname(const char *name, const char *path);
std::string resolve_name(uint64_t name_id);
std::vector<uint64_t> get_arg_values(std::vector<Field> args, uint8_t* arg_data);
void format_impl(std::stringstream& ss, const char* format);
template <typename Arg, typename... Args>
void format_impl(std::stringstream& ss, const char* format, Arg arg, Args... args);
template <typename... Args>
std::string format(const char* fmt, Args... args);
template <typename... Args>
std::string format_string(const char* fmt, Args... args);
int pid_;
std::map<std::string, std::unique_ptr<IMap>> maps_;
std::map<std::string, Struct> structs_;
std::vector<std::tuple<std::string, std::vector<Field>>> printf_args_;
std::vector<std::tuple<std::string, std::vector<Field>>> system_args_;
std::vector<std::string> time_args_;
std::unique_ptr<IMap> stackid_map_;
std::unique_ptr<IMap> join_map_;
......
......@@ -89,7 +89,8 @@ public:
enum class AsyncAction
{
// printf reserves 0-9999 for printf_ids
exit = 10000,
syscall = 10000, // system reserves 10000-19999 for printf_ids
exit = 20000,
print,
clear,
zero,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment