namespace bpf {
+// Constants for BPF code generation.
+// TODO: BPF_MAX{STRING,FORMAT}LEN,BPF_MAXMAPENTRIES,BPF_MAXSPRINTFLEN should be user-configurable.
+
#define MAX_BPF_STACK 512
#define BPF_REG_SIZE 8
+
#define BPF_MAXSTRINGLEN 64
-// #define BPF_MAXSTRINGLEN 128 // TODO: Longer strings require storage allocator & PR22330 better printf().
+// #define BPF_MAXSTRINGLEN 128 // TODO: Longer strings require a smarter storage allocator.
+#define BPF_MAXFORMATLEN 256
#define BPF_MAXPRINTFARGS 32
// #define BPF_MAXPRINTFARGS 3 // Maximum for trace_printk() method.
-#define BPF_MAXFORMATLEN 256
+#define BPF_MAXSPRINTFARGS 3 // Maximum for sprintf() method.
+
#define BPF_MAXMAPENTRIES 2048
-// TODO: add BPF_MAXSPRINTFLEN
-// TODO: BPF_MAX{STRING,FORMAT}LEN,BPF_MAXMAPENTRIES,BPF_MAXSPRINTFLEN should be user-configurable.
// XXX: BPF_MAXMAPENTRIES may depend on kernel version. May need to experiment with rlimit in instantiate_maps().
-// TODOXXX: Constants for transport message layout. Try to reduce the size (to __u32) while keeping proper alignment.
-#define BPF_TRANSPORT_VAL __u64
-#define BPF_TRANSPORT_ARG __u64
+// Constants for transport message layout.
+// TODO: Try to reduce the size (to __u32) while keeping proper alignment.
+#define BPF_TRANSPORT_VAL uint64_t
+#define BPF_TRANSPORT_ARG uint64_t
// XXX: BPF_TRANSPORT_ARG is for small numerical arguments, not pe_long values.
-// TODOXXX: Use sizeof(BPF_TRANSPORT_*) instead of magic numbers throughout.
// Will print out bpf assembly before and after optimization:
//#define DEBUG_CODEGEN
{
value *dest = get_asm_reg(stmt, stmt.dest);
this_prog.mk_mov(this_ins, dest, retval);
-
}
// ??? For diagnostics: check other cases with retval and stmt.dest.
}
this_prog.mk_binary(this_ins, BPF_ADD, out,
dest, this_prog.new_imm(ofs));
-
#ifdef DEBUG_CODEGEN
this_ins.notes.pop(); // strcpy
#endif
assert(false); // XXX: Should be caught earlier.
}
- // TODOXXX: add code to ensure alignment, depending on argument size.
+ // XXX: The following force-aligns all elements to double word boundary.
+ // Could probably switch to single-word alignment with more careful design.
if (arg_size % 8 != 0)
- arg_size += 8 - arg_size % 8; // double word -- XXX verifier forces aligned access
+ arg_size += 8 - arg_size % 8;
int arg_ofs = -arg_size;
- int msg_ofs = arg_ofs-sizeof(BPF_TRANSPORT_VAL); // double word -- XXX verifier forces aligned access
- assert(msg_ofs % 8 == 0);
+ int msg_ofs = arg_ofs-sizeof(BPF_TRANSPORT_VAL);
+ if (msg_ofs % 8 != 0)
+ msg_ofs -= (8 - (-msg_ofs) % 8);
this_prog.use_tmp_space(-msg_ofs);
value *frame = this_prog.lookup_reg(BPF_REG_10);
if (!print_to_stream)
{
+ // TODO: sprintf() has an additional constraint on arguments due
+ // to passing them in a very small number of registers.
+ if (actual.size() > BPF_MAXSPRINTFARGS)
+ throw SEMANTIC_ERROR(_NF("additional argument to sprintf",
+ "too many arguments to sprintf (%zu)",
+ actual.size(), e->args.size()), tok);
+
// Emit an ordinary function call to sprintf.
size_t format_bytes = format.size() + 1;
this_prog.mk_mov(this_ins, this_prog.lookup_reg(BPF_REG_1),
return -1;
}
-// TODOXXX: Adapt to MAXPRINTFARGS == 32.
+// TODO: Adapt to MAXPRINTFARGS == 32.
uint64_t
bpf_sprintf(std::vector<std::string> &strings, char *fstr,
uint64_t arg1, uint64_t arg2, uint64_t arg3)
for (unsigned i = 0; i < BPF_MAXPRINTFARGS; i++)
if (i < ctx->printf_args.size()
&& ctx->printf_arg_types[i] == bpf::globals::STP_PRINTF_ARG_LONG)
- fargs[i] = (void *)*(__u64*)ctx->printf_args[i]; // TODOXXX: Fixup for 32-bit systems?
+ fargs[i] = (void *)*(uint64_t*)ctx->printf_args[i]; // TODOXXX: Fixup for 32-bit systems?
else if (i < ctx->printf_args.size())
fargs[i] = ctx->printf_args[i];
else
// Used by the transport layer and interpreter:
struct bpf_transport_context {
+ // XXX: The following two fields are only used for kernel programs.
+ // pmu_fd == -1 indicates context for a userspace interpreter.
unsigned cpu;
int pmu_fd;
- // TODOXXX: If pmu_fd == -1, this is a userspace context. Be sure to reflect this in diagnostics.
// References to global state:
std::vector<int> *map_fds;
static std::vector<trace_data> tracepoint_probes;
static std::vector<uprobe_data> uprobes;
-// TODOXXX: Move fatal() to bpfinterp.h and replace abort() calls in the interpreter.
-// TODOXXX: Add warn() option.
-
+// TODO: Move fatal() to bpfinterp.h and replace abort() calls in the interpreter.
+// TODO: Add warn() option.
static void __attribute__((noreturn))
fatal(const char *str, ...)
{
if (log_level > 3)
fprintf(stderr, "Polling for perf_event data on %d cpus...\n", ncpus);
int ready = poll(pmu_fds, ncpus, 1000); // XXX: Consider setting timeout -1 (unlimited).
- if (ready < 0 && errno == EINTR) // TODOXXX: Check that we really received a signal.
+ if (ready < 0 && errno == EINTR)
goto signal_exit;
if (ready < 0)
fatal("Error checking for perf events: %s\n", strerror(errno));
return;
}
-// TODOXXX PR22330: remove this older code.
-#if 0
-static void
-print_trace_output(pthread_t main_thread)
-{
- // Output from printf statements within probe handlers is sent to
- // debugfs via trace_printk. Get this output and copy it to output_f.
- string modname(module_name);
- size_t pos = modname.find_last_of("/");
- if (pos != string::npos)
- modname = modname.substr(pos + 1);
-
- string start_tag = "<" + modname.erase(modname.size() - 3).erase(4, 1) + ">";
- string end_tag = start_tag;
- end_tag.insert(1, "/");
-
- while (1)
- {
- ifstream trace_pipe(DEBUGFS "trace_pipe");
- if (!trace_pipe)
- fatal("error opening trace_pipe: %s\n", strerror(errno));
-
- bool start_tag_seen = false;
- unsigned bytes_written = 0;
- string line, buf;
- while (getline(trace_pipe, line))
- {
- line += "\n";
- if (!start_tag_seen)
- {
- pos = line.find(start_tag);
- if (pos != string::npos)
- {
- start_tag_seen = true;
- bytes_written = 0;
- line = line.substr(pos + start_tag.size(), string::npos);
- }
- }
- if (start_tag_seen)
- {
- pos = line.find(end_tag);
- if (pos != string::npos)
- {
- line = line.substr(0, pos);
- start_tag_seen = false;
-
- // exit() causes "" to be written to trace_pipe. If
- // "" is seen and the exit flag is set, wake up main
- // thread to begin program shutdown.
- if (line == "" && buf == "" && bytes_written == 0
- && get_exit_status())
- {
- pthread_kill(main_thread, SIGINT);
- return;
- }
- }
-
- buf += line;
- if (fwrite(buf.c_str(), sizeof(char), buf.size(), output_f)
- != buf.size())
- fatal("error writing to output file: %s\n", strerror(errno));
- bytes_written += buf.size();
-
- fflush(output_f);
- buf = "";
- }
- }
- // If another process opens trace_pipe then we may read EOF. In this
- // case simply reopen the file and continue parsing.
- }
-}
-#endif
-
static void
usage(const char *argv0)
{
// PR22330: Listen for perf_events:
std::thread(perf_event_loop, pthread_self()).detach();
- //std::thread(print_trace_output, pthread_self()).detach(); // TODOXXX: remove this older code.
// Now that the begin probe has run and the perf_event listener is active, enable the kprobes.
ioctl(group_fd, PERF_EVENT_IOC_ENABLE, 0);