diff --git a/.gitignore b/.gitignore index e49c437..8bcb45a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/systemtap-4.0.tar.gz +SOURCES/systemtap-4.1.tar.gz diff --git a/.systemtap.metadata b/.systemtap.metadata index eb6d659..bbcb4c0 100644 --- a/.systemtap.metadata +++ b/.systemtap.metadata @@ -1 +1 @@ -40a21d71b0d42bc216f75befd3fca82701821211 SOURCES/systemtap-4.0.tar.gz +d3653e17960ac8bb23be3bb57dfa4b17dcb9d27d SOURCES/systemtap-4.1.tar.gz diff --git a/SOURCES/pr23074.patch b/SOURCES/pr23074.patch new file mode 100644 index 0000000..76e0201 --- /dev/null +++ b/SOURCES/pr23074.patch @@ -0,0 +1,51 @@ +commit 83071bc877b462eacca309fa49c9e8112fc16bdf +Author: Jafeer Uddin +Date: Thu May 9 16:18:46 2019 -0400 + + PR23074: fix guru mode issue with generated calls to register get/set + +diff --git a/elaborate.cxx b/elaborate.cxx +index 9ebf30b..fcd1d1d 100644 +--- a/elaborate.cxx ++++ b/elaborate.cxx +@@ -3073,7 +3073,7 @@ public: + } + + // Don't allow /* guru */ functions unless caller is privileged. +- if (!call->tok->location.file->privileged && ++ if (!call->synthetic && !call->tok->location.file->privileged && + s->tagged_p ("/* guru */")) + throw SEMANTIC_ERROR (_("function may not be used unless -g is specified"), + call->tok); +diff --git a/loc2stap.cxx b/loc2stap.cxx +index c1a48d0..d4fd051 100644 +--- a/loc2stap.cxx ++++ b/loc2stap.cxx +@@ -1745,6 +1745,7 @@ location_context::handle_GNU_parameter_ref (Dwarf_Op expr) + // it and we want to be able to restore the registers back. + functioncall *get_ptregs = new functioncall; + get_ptregs->tok = e->tok; ++ get_ptregs->synthetic = true; + if (this->userspace_p) + get_ptregs->function = std::string("__get_uregs"); + else +@@ -1870,6 +1871,7 @@ location_context::handle_GNU_parameter_ref (Dwarf_Op expr) + // Translation done, restore the pt_regs to its original value + functioncall *set_ptregs = new functioncall; + set_ptregs->tok = e->tok; ++ set_ptregs->synthetic = true; + if (this->userspace_p) + set_ptregs->function = std::string("__set_uregs"); + else +diff --git a/staptree.h b/staptree.h +index d63156f..2735808 100644 +--- a/staptree.h ++++ b/staptree.h +@@ -464,6 +464,7 @@ struct functioncall: public expression + interned_string function; + std::vector args; + std::vector referents; ++ bool synthetic; + functioncall (); + void print (std::ostream& o) const; + void visit (visitor* u); diff --git a/SOURCES/pr23875_bugfix.patch b/SOURCES/pr23875_bugfix.patch new file mode 100644 index 0000000..32884de --- /dev/null +++ b/SOURCES/pr23875_bugfix.patch @@ -0,0 +1,148 @@ +commit e037dc796de75b0d9e7e893fba6a39c2837aca2b +Author: Serhei Makarov +Date: Wed Jul 31 13:25:19 2019 -0400 + + stapbpf pr23875 bugfix :: allocate actual keysize in foreach to avoid stack clobber + + * bpf-translate.cxx (bpf_unparser::visit_foreach_loop): allocate actual keysize. + * testsuite/systemtap.bpf/bpf_tests/foreach_string.stp: new partial PR23858 testcase, + added only the parts necessary to trigger a segfault when bugfix not applied. + +diff --git a/bpf-translate.cxx b/bpf-translate.cxx +index b254be693..720e23d4e 100644 +--- a/bpf-translate.cxx ++++ b/bpf-translate.cxx +@@ -1797,7 +1797,7 @@ bpf_unparser::visit_foreach_loop(foreach_loop* s) + this_prog.mk_jcond (this_ins, NE, this_prog.lookup_reg(BPF_REG_0), i0, + join_block, load_block); + +- this_prog.use_tmp_space(16); ++ this_prog.use_tmp_space(2*keysize); + + emit_jmp(load_block); + +diff --git a/testsuite/systemtap.bpf/bpf_tests/foreach_string.stp b/testsuite/systemtap.bpf/bpf_tests/foreach_string.stp +new file mode 100644 +index 000000000..956b1b409 +--- /dev/null ++++ b/testsuite/systemtap.bpf/bpf_tests/foreach_string.stp +@@ -0,0 +1,119 @@ ++global a[10], b[10] ++ ++probe begin { ++ printf("BEGIN\n") ++ ++ a["p"] = -1 ++ a["q"] = 0 ++ a["r"] = 1 ++ ++ b[-1] = "p" ++ b[0] = "q" ++ b[1] = "r" ++ ++ exit() ++} ++ ++global flag = 1 ++global _flag = 1 ++ ++// XXX Split into separate probes due to stack size constraint. ++global end_probes = 0 // TODO: Remove this workaround for PR24812. ++ ++probe end(1) { ++ printf("first end probe\n") ++ ++ /* TODO: Requires PR23858. ++ foreach (ks- in a limit -10) ++ flag = 0 ++ ++ foreach (ks- in a limit 0) ++ flag = 0 ++ ++ found = 0 ++ foreach (ks+ in a limit 1) { ++ found++ ++ if (a[ks] != -1) ++ flag = 0 ++ } ++ ++ foreach (k in b+ limit 1) { ++ found++ ++ if (k != -1) ++ flag = 0 ++ } ++ if (found != 2) ++ flag = 0 ++ ++ foreach (ks1 in a limit 0) ++ foreach (ks2 in a) ++ flag = 0 ++ ++ foreach (ks1 in a) ++ foreach (ks2 in a limit 0) ++ flag = 0 ++ */ ++ ++ x = 0 ++ foreach (ks in a) ++ x += a[ks] ++ flag = flag && x == 0 ++ ++ if (end_probes == 0) ++ end_probes++ ++ // { end_probes++; next; } // TODO: Investigate using next here. ++ else if (flag) ++ printf("END PASS\n") ++ else ++ printf("END FAIL\n") ++} ++ ++probe end(2) { ++ printf("second end probe\n") ++ ++ /* TODO: Requires PR23858. ++ x = -1 ++ foreach (ks+ in a) ++ flag = flag && x++ == a[ks] ++ flag = flag && x == 2 ++ ++ x = 1 ++ foreach (ks- in a) ++ { ++ flag = flag && x-- == a[ks] ++ } ++ flag = flag && x == -2 ++ ++ x = -1 ++ y = 2 ++ foreach (ks1+ in a) { ++ foreach (k2 in b-) ++ { ++ printf("got %s %d / %d %s\n", ks1, a[ks1], k2, b[k2]) ++ flag = flag && x == a[ks1] ++ && y-- == k2 ++ } ++ x++ ++ y = 2 ++ } ++ */ ++ ++ x = -1 ++ y = 1 ++ foreach (ks1+ in a) { ++ foreach (ks2- in a) ++ // TODO: Requires PR23858. ++ _flag = _flag && x == a[ks1] ++ && y-- == a[ks2] ++ x++ ++ y = 1 ++ } ++ ++ if (end_probes == 0) ++ end_probes++ ++ // { end_probes++; next; } // TODO: Investigate using next here. ++ else if (flag) ++ printf("END PASS\n") ++ else ++ printf("END FAIL\n") ++} diff --git a/SOURCES/rhbz1643997.0001-testsuite-systemtap.bpf-diagnose-a-bug-in-print_form.patch b/SOURCES/rhbz1643997.0001-testsuite-systemtap.bpf-diagnose-a-bug-in-print_form.patch deleted file mode 100644 index d0af424..0000000 --- a/SOURCES/rhbz1643997.0001-testsuite-systemtap.bpf-diagnose-a-bug-in-print_form.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 16e9cfa909a183d8e61142d80575189408a2a244 Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Wed, 24 Oct 2018 15:56:44 -0400 -Subject: [PATCH 01/32] testsuite/systemtap.bpf :: diagnose a bug in - print_format("%s%s", ...) - ---- - testsuite/systemtap.bpf/asm_tests/string-basic.stp | 19 ++++++++++ - testsuite/systemtap.bpf/bpf_tests/string3.stp | 44 ++++++++++++++++++++++ - 2 files changed, 63 insertions(+) - create mode 100644 testsuite/systemtap.bpf/asm_tests/string-basic.stp - create mode 100644 testsuite/systemtap.bpf/bpf_tests/string3.stp - -diff --git a/testsuite/systemtap.bpf/asm_tests/string-basic.stp b/testsuite/systemtap.bpf/asm_tests/string-basic.stp -new file mode 100644 -index 000000000..7377e4399 ---- /dev/null -+++ b/testsuite/systemtap.bpf/asm_tests/string-basic.stp -@@ -0,0 +1,19 @@ -+/* narrowing down a bug that turned out unrelated to assembly */ -+function foo:string() %{ /* bpf */ /* pure */ -+ 0xbf, $$, "test", -, -; -+%} -+ -+probe begin { -+ printf("U %s %s\n", foo(), "test"/*bar (5)*/) -+} -+ -+probe kernel.function("vfs_read") { -+ printf("K 1 %s\n", foo()) // <- this worked -+ printf("K 2 %s\n", "test") // <- this worked -+ printf("K 3 %s %s\n", foo(), "test") // <- this didn't -+ printf("K 4 %s %s\n", "test", "test") // <- this didn't -+ printf("K 5 %s %s\n", foo(), foo()) // <- this didn't -+ printf("K 6 %s", "test") printf(" %s\n", "test") // <- this did -+ printf("K %d %s\n", 7, "test") // <- this did -+ exit() -+} -diff --git a/testsuite/systemtap.bpf/bpf_tests/string3.stp b/testsuite/systemtap.bpf/bpf_tests/string3.stp -new file mode 100644 -index 000000000..cf6ec071d ---- /dev/null -+++ b/testsuite/systemtap.bpf/bpf_tests/string3.stp -@@ -0,0 +1,44 @@ -+// stapbpf string manipulation -- store string in global from kernel space -+// XXX: the 'locking' scheme here is kind of dumb but it seems to work -+ -+global counter = 0 -+global var -+global tab1 -+global tab2 -+ -+@define test_print -+%( -+ /* Test multiple %s in one printf */ -+ printf("[") -+ printf("%s%s%s", "str0", var, tab1[17]) -+ printf("%s]", tab2["key"]) -+%) -+ -+probe begin { -+ printf("BEGIN") -+} -+ -+probe kernel.function("vfs_read") { -+ if (counter == 0) { -+ var = "str1" -+ tab1[17] = "str2" -+ tab2["key"] = "str3" -+ printf("probe0") -+ @test_print -+ counter = 1 -+ } -+} -+ -+probe kernel.function("vfs_read") { -+ if (counter == 1) { -+ printf("probe1") -+ @test_print -+ exit() -+ } -+} -+ -+probe end { -+ printf("end") -+ @test_print -+ printf("END\n") -+} --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0002-stapbpf-assembler-WIP-1-basic-parser-and-control-flo.patch b/SOURCES/rhbz1643997.0002-stapbpf-assembler-WIP-1-basic-parser-and-control-flo.patch deleted file mode 100644 index ed6c8bd..0000000 --- a/SOURCES/rhbz1643997.0002-stapbpf-assembler-WIP-1-basic-parser-and-control-flo.patch +++ /dev/null @@ -1,945 +0,0 @@ -From 17d4495bef5c3878bb38730ff0d849415b52641a Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Mon, 1 Oct 2018 15:38:16 -0400 -Subject: [PATCH 02/32] stapbpf assembler WIP #1 :: basic parser and control - flow - ---- - bpf-internal.h | 7 +- - bpf-opt.cxx | 2 +- - bpf-translate.cxx | 745 +++++++++++++++++++++++++++++++++++++++++++----------- - parse.h | 14 + - 4 files changed, 619 insertions(+), 149 deletions(-) - -diff --git a/bpf-internal.h b/bpf-internal.h -index 17a033533..719446db8 100644 ---- a/bpf-internal.h -+++ b/bpf-internal.h -@@ -261,9 +261,10 @@ struct program - void print(std::ostream &) const; - }; - --// ??? Properly belongs to bpf_unparser but must be accessible from bpf-opt.cxx: --value *emit_literal_str(program &this_prog, insn_inserter &this_ins, -- value *dest, int ofs, std::string &src, bool zero_pad = false); -+// ??? Properly belongs to bpf_unparser but must be visible from bpf-opt.cxx: -+value *emit_simple_literal_str(program &this_prog, insn_inserter &this_ins, -+ value *dest, int ofs, std::string &src, -+ bool zero_pad = false); - - inline std::ostream& - operator<< (std::ostream &o, const program &c) -diff --git a/bpf-opt.cxx b/bpf-opt.cxx -index 0f64d826d..c2e30a690 100644 ---- a/bpf-opt.cxx -+++ b/bpf-opt.cxx -@@ -41,7 +41,7 @@ alloc_literal_str(program &p, insn_inserter &ins, std::string &str) - int ofs = -tmp_space; - - value *frame = p.lookup_reg(BPF_REG_10); -- value *out = emit_literal_str(p, ins, frame, ofs, str, false /* don't zero pad */); -+ value *out = emit_simple_literal_str(p, ins, frame, ofs, str, false /* don't zero pad */); - return out; - } - -diff --git a/bpf-translate.cxx b/bpf-translate.cxx -index d848c9f16..023ac6ce7 100644 ---- a/bpf-translate.cxx -+++ b/bpf-translate.cxx -@@ -8,6 +8,7 @@ - - #include "config.h" - #include "bpf-internal.h" -+#include "parse.h" - #include "staptree.h" - #include "elaborate.h" - #include "session.h" -@@ -134,6 +135,9 @@ has_side_effects (expression *e) - return t.side_effects; - } - -+/* forward declaration */ -+struct asm_stmt; -+ - struct bpf_unparser : public throwing_visitor - { - // The visitor class isn't as helpful as it might be. As a consequence, -@@ -233,10 +237,19 @@ struct bpf_unparser : public throwing_visitor - value *emit_expr(expression *e); - value *emit_bool(expression *e); - value *emit_context_var(bpf_context_vardecl *v); -- value *parse_reg(const std::string &str, embeddedcode *s); - -- // Used for copying string data: -- value *emit_copied_str(value *dest, int ofs, value *src, bool zero_pad = false); -+ // Used for the embedded-code assembler: -+ size_t parse_asm_stmt (embeddedcode *s, size_t start, -+ /*OUT*/asm_stmt &stmt); -+ value *emit_asm_arg(const asm_stmt &stmt, const std::string ®, -+ bool allow_imm = true); -+ value *emit_asm_reg(const asm_stmt &stmt, const std::string ®); -+ void emit_asm_opcode(const asm_stmt &stmt, -+ std::map label_map); -+ -+ // Used for string data: -+ value *emit_literal_string(const std::string &str, const token *tok); -+ value *emit_string_copy(value *dest, int ofs, value *src, bool zero_pad = false); - - // Used for passing long and string arguments on the stack where an address is expected: - void emit_long_arg(value *arg, int ofs, value *val); -@@ -552,172 +565,604 @@ bpf_unparser::visit_block (::block *s) - emit_stmt (s->statements[i]); - } - -+/* WORK IN PROGRESS: A simple eBPF assembler. -+ -+ In order to effectively write eBPF tapset functions, we want to use -+ embedded-code assembly rather than compile from SystemTap code. At -+ the same time, we want to hook into stapbpf functionality to -+ reserve stack memory, allocate virtual registers or signal errors. -+ -+ The assembler syntax will probably take a couple of attempts to get -+ just right. This attempt keeps things as close as possible to the -+ first embedded-code assembler, with a few more features and a -+ disgustingly lenient parser that allows things like -+ $ this is all one "**identifier**" believe-it!-or-not -+ -+ Ahh for the days of 1960s FORTRAN. -+ -+ TODO: It might make more sense to implement an assembler based on -+ the syntax used in official eBPF subsystem docs. */ -+ -+/* Possible assembly statement types include: -+ -+ ::= label, ; -+ ::= , , , -+ , ; -+ -+ Possible argument types include: -+ -+ ::= | r | -+ $ | $ | $$ | -+ ::= | BPF_MAXSTRINGLEN -+ ::= | -+ -+*/ -+ -+struct asm_stmt { -+ std::string kind; -+ -+ unsigned code; -+ std::string dest, src1; -+ int64_t off, imm; -+ -+ // metadata for jmp instructions -+ bool has_fallthrough = false; -+ std::string jmp_target, fallthrough; -+ -+ token *tok; -+ bool deallocate_tok = false; -+ ~asm_stmt() { if (deallocate_tok) delete tok; } -+}; -+ -+std::ostream& -+operator << (std::ostream& o, const asm_stmt& stmt) -+{ -+ if (stmt.kind == "label") -+ o << "label, " << stmt.dest << ";"; -+ else if (stmt.kind == "opcode") -+ { -+ o << std::hex << stmt.code << ", " -+ << stmt.dest << ", " -+ << stmt.src1 << ", "; -+ if (stmt.off != 0 || stmt.jmp_target == "") -+ o << stmt.off; -+ else if (stmt.off != 0) // && stmt.jmp_target != "" -+ o << stmt.off << "/"; -+ if (stmt.jmp_target != "") -+ o << "label:" << stmt.jmp_target; -+ o << ", " -+ << stmt.imm << ";" -+ << (stmt.has_fallthrough ? " +FALLTHROUGH " + stmt.fallthrough : ""); -+ } -+ else -+ o << ""; -+ return o; -+} -+ -+bool -+is_numeric (const std::string &str) -+{ -+ size_t pos = 0; -+ try { -+ stol(str, &pos, 0); -+ } catch (std::invalid_argument &e) { -+ return false; -+ } -+ return (pos == str.size()); -+} -+ -+/* Parse an assembly statement starting from position start in code, -+ then write the output in stmt. Returns a position immediately after -+ the parsed statement. */ -+size_t -+bpf_unparser::parse_asm_stmt (embeddedcode *s, size_t start, -+ /*OUT*/asm_stmt &stmt) -+{ -+ const interned_string &code = s->code; -+ -+ retry: -+ std::vector args; -+ unsigned n = code.size(); -+ bool in_comment = false; -+ bool in_string = false; -+ -+ // compute token with adjusted source location for diagnostics -+ source_loc adjusted_loc; // TODO: ought to create a proper copy constructor for source_loc -+ adjusted_loc.file = s->tok->location.file; -+ adjusted_loc.line = s->tok->location.line; -+ adjusted_loc.column = s->tok->location.column; -+ for (size_t pos = 0; pos < start && pos < n; pos++) -+ { -+ // TODO: should save adjusted_loc state between parse_asm_stmt invocations; add field? -+ char c = code[pos]; -+ if (c == '\n') -+ { -+ adjusted_loc.line++; -+ adjusted_loc.column = 1; -+ } -+ else -+ adjusted_loc.column++; -+ } -+ -+ // TODO: As before, parser is extremely non-rigorous and could do -+ // with some tightening in terms of the inputs it accepts. -+ size_t pos; -+ std::string arg = ""; -+ for (pos = start; pos < n; pos++) -+ { -+ char c = code[pos]; -+ char c2 = pos + 1 < n ? code [pos + 1] : 0; -+ if (isspace(c)) -+ continue; // skip -+ else if (in_comment) -+ { -+ if (c == '*' && c2 == '/') -+ ++pos, in_comment = false; -+ // else skip -+ } -+ else if (in_string) -+ { -+ // resulting string will be processed by translate_escapes() -+ if (c == '"') -+ arg.push_back(c), in_string = false; // include quote -+ else if (c == '\\' && c2 == '"') -+ ++pos, arg.push_back(c), arg.push_back(c2); -+ else // accept any char, including whitespace -+ arg.push_back(c); -+ } -+ else if (c == '/' && c2 == '*') -+ ++pos, in_comment = true; -+ else if (c == '"') // found a literal string -+ { -+ // XXX: This allows '"' inside an arg and will treat the -+ // string as a sequence of weird identifier characters. A -+ // more rigorous parser would error on mixing strings and -+ // regular chars. -+ arg.push_back(c); // include quote -+ in_string = true; -+ } -+ else if (c == ',') // reached end of argument -+ { -+ // XXX: This strips out empty args. A more rigorous parser would error. -+ if (arg != "") -+ args.push_back(arg); -+ arg = ""; -+ } -+ else if (c == ';') // reached end of statement -+ { -+ // XXX: This strips out empty args. A more rigorous parser would error. -+ if (arg != "") -+ args.push_back(arg); -+ arg = ""; -+ pos++; break; -+ } -+ else // found (we assume) a regular char -+ { -+ // XXX: As before, this strips whitespace within args -+ // (so '$ab', '$ a b' and '$a b' are equivalent). -+ // -+ // A more rigorous parser would track in_arg -+ // and after_arg states and error on whitespace within args. -+ arg.push_back(c); -+ } -+ } -+ // final ';' is optional, so we watch for a trailing arg: -+ if (arg != "") args.push_back(arg); -+ -+ // handle the case with no args -+ if (args.empty() && pos >= n) -+ return std::string::npos; // finished parsing -+ else if (args.empty()) -+ { -+ // XXX: This skips an empty statement. -+ // A more rigorous parser would error. -+ start = pos; -+ goto retry; -+ } -+ -+ // set token with adjusted source location -+ //stmt.tok = (token *)s->tok; -+ // TODO this segfaults for some reason, some data not copied? -+ stmt.tok = s->tok->adjust_location(adjusted_loc); -+ stmt.deallocate_tok = false; // TODO must avoid destroy-on-copy -+ -+ std::cerr << "DEBUG GOT stmt "; // TODO -+ for (unsigned k = 0; k < args.size(); k++) std::cerr << args[k] << " / "; -+ std::cerr << std::endl; // TODO -+ if (args[0] == "label") -+ { -+ if (args.size() != 2) -+ throw SEMANTIC_ERROR (_("invalid bpf embeddedcode syntax"), stmt.tok); -+ stmt.kind = args[0]; -+ stmt.dest = args[1]; -+ } -+ else if (is_numeric(args[0])) -+ { -+ if (args.size() != 5) // TODO change to 4 to test err+tok -+ throw SEMANTIC_ERROR (_("invalid bpf embeddedcode syntax"), stmt.tok); -+ stmt.kind = "opcode"; -+ stmt.code = stoul(args[0], 0, 0); // TODO signal error -+ stmt.dest = args[1]; -+ stmt.src1 = args[2]; -+ -+ bool has_jmp_target = -+ BPF_CLASS(stmt.code) == BPF_JMP -+ && BPF_OP(stmt.code) != BPF_EXIT -+ && BPF_OP(stmt.code) != BPF_CALL; -+ stmt.has_fallthrough = // only for jcond -+ has_jmp_target -+ && BPF_OP(stmt.code) != BPF_JA; -+ // XXX: stmt.fallthrough is computed by visit_embeddedcode -+ -+ if (has_jmp_target) -+ { -+ stmt.off = 0; -+ stmt.jmp_target = args[3]; -+ } -+ else if (args[3] == "BPF_MAXSTRINGLEN") -+ stmt.off = BPF_MAXSTRINGLEN; -+ else if (args[3] == "-") -+ stmt.off = 0; -+ else -+ stmt.off = stol(args[3]); // TODO signal error -+ -+ if (args[4] == "BPF_MAXSTRINGLEN") -+ stmt.imm = BPF_MAXSTRINGLEN; -+ else if (args[4] == "-") -+ stmt.imm = 0; -+ else -+ stmt.imm = stol(args[4]); // TODO signal error -+ } -+ else -+ throw SEMANTIC_ERROR (_F("unknown bpf embeddedcode operator '%s'", -+ args[0].c_str()), stmt.tok); -+ -+ // we returned a statement, so there's more parsing to be done -+ return pos; -+} -+ -+/* forward declaration */ -+std::string translate_escapes (const interned_string &str); -+ -+/* Convert a or operand to a value. -+ May emit code to store a string constant on the stack. */ - value * --bpf_unparser::parse_reg(const std::string &str, embeddedcode *s) -+bpf_unparser::emit_asm_arg (const asm_stmt &stmt, const std::string &arg, -+ bool allow_imm) - { -- if (str == "$$") -+ if (arg == "$$") - { -- if (func_return.empty ()) -- throw SEMANTIC_ERROR (_("no return value outside function"), s->tok); -+ /* arg is a return value */ -+ if (func_return.empty()) -+ throw SEMANTIC_ERROR (_("no return value outside function"), stmt.tok); - return func_return_val.back(); - } -- else if (str[0] == '$') -+ else if (arg[0] == '$') - { -- std::string var = str.substr(1); -+ /* assume arg is a variable */ -+ std::string var = arg.substr(1); - for (auto i = this_locals->begin(); i != this_locals->end(); ++i) - { - vardecl *v = i->first; - if (var == v->unmangled_name) - return i->second; - } -- throw SEMANTIC_ERROR (_("unknown variable"), s->tok); -+ -+ /* if it's an unknown variable, allocate a temporary */ -+ struct vardecl *vd = new vardecl; -+ vd->name = "__bpfasm__local_" + var; -+ vd->unmangled_name = var; -+ vd->type = pe_long; -+ vd->arity = 0; -+ value *reg = this_prog.new_reg(); -+ const locals_map::value_type v (vd, reg); -+ auto ok = this_locals->insert (v); -+ assert (ok.second); -+ return reg; -+ // TODO write a testcase - } -- else -+ else if (is_numeric(arg) && allow_imm) - { -- unsigned long num = stoul(str, 0, 0); -+ /* arg is an immediate constant */ -+ long imm = stol(arg, 0, 0); -+ return this_prog.new_imm(imm); -+ } -+ else if (is_numeric(arg) || arg[0] == 'r') -+ { -+ /* arg is a register number */ -+ std::string reg = arg[0] == 'r' ? arg.substr(1) : arg; -+ unsigned long num = stoul(reg, 0, 0); - if (num > 10) -- throw SEMANTIC_ERROR (_("invalid bpf register"), s->tok); -+ throw SEMANTIC_ERROR (_F("invalid bpf register '%s'", -+ arg.c_str()), stmt.tok); - return this_prog.lookup_reg(num); - } -+ else if (arg[0] == '"') -+ { -+ // TODO verify correctness -+ /* arg is a string constant */ -+ if (arg[arg.size() - 1] != '"') -+ throw SEMANTIC_ERROR (_F("BUG: improper string %s", -+ arg.c_str()), stmt.tok); -+ std::string escaped_str = arg.substr(1,arg.size()-2); /* strip quotes */ -+ std::string str = translate_escapes(escaped_str); // TODO interned_str? -+ return emit_literal_string(str, stmt.tok); -+ } -+ else if (arg == "BPF_MAXSTRINGLEN") -+ { -+ /* arg is BPF_MAXSTRINGLEN */ -+ if (!allow_imm) -+ throw SEMANTIC_ERROR (_F("invalid bpf register '%s'", -+ arg.c_str()), stmt.tok); -+ return this_prog.new_imm(BPF_MAXSTRINGLEN); -+ } -+ else if (arg == "-") -+ { -+ /* arg is null a.k.a '0' */ -+ if (!allow_imm) -+ throw SEMANTIC_ERROR (_F("invalid bpf register '%s'", -+ arg.c_str()), stmt.tok); -+ return this_prog.new_imm(0); -+ } -+ else if (allow_imm) -+ throw SEMANTIC_ERROR (_F("invalid bpf argument '%s'", -+ arg.c_str()), stmt.tok); -+ else -+ throw SEMANTIC_ERROR (_F("invalid bpf register '%s'", -+ arg.c_str()), stmt.tok); -+ -+} -+ -+value * -+bpf_unparser::emit_asm_reg (const asm_stmt &stmt, const std::string ®) -+{ -+ return emit_asm_arg(stmt, reg, /*allow_imm=*/false); - } - - void --bpf_unparser::visit_embeddedcode (embeddedcode *s) -+bpf_unparser::emit_asm_opcode (const asm_stmt &stmt, -+ std::map label_map) - { -- std::string strip; -- { -- const interned_string &code = s->code; -- unsigned n = code.size(); -- bool in_comment = false; -+ if (stmt.code > 0xff && stmt.code != BPF_LD_MAP) -+ throw SEMANTIC_ERROR (_("invalid bpf code"), stmt.tok); - -- for (unsigned i = 0; i < n; ++i) -- { -- char c = code[i]; -- if (isspace(c)) -- continue; -- if (in_comment) -- { -- if (c == '*' && code[i + 1] == '/') -- ++i, in_comment = false; -- } -- else if (c == '/' && code[i + 1] == '*') -- ++i, in_comment = true; -- else -- strip += c; -- } -- } -+ bool r_dest = false, r_src0 = false, r_src1 = false, i_src1 = false; -+ bool op_jmp = false, op_jcond = false; condition c; -+ switch (BPF_CLASS (stmt.code)) -+ { -+ case BPF_LDX: -+ r_dest = r_src1 = true; -+ break; -+ case BPF_STX: -+ r_src0 = r_src1 = true; -+ break; -+ case BPF_ST: -+ r_src0 = i_src1 = true; -+ break; -+ -+ case BPF_ALU: -+ case BPF_ALU64: -+ r_dest = true; -+ if (stmt.code & BPF_X) -+ r_src1 = true; -+ else -+ i_src1 = true; -+ switch (BPF_OP (stmt.code)) -+ { -+ case BPF_NEG: -+ case BPF_MOV: -+ break; -+ case BPF_END: -+ /* X/K bit repurposed as LE/BE. */ -+ i_src1 = false, r_src1 = true; -+ break; -+ default: -+ r_src0 = true; -+ } -+ break; -+ -+ case BPF_JMP: -+ switch (BPF_OP (stmt.code)) -+ { -+ case BPF_EXIT: -+ // no special treatment needed -+ break; -+ case BPF_CALL: -+ i_src1 = true; -+ break; -+ case BPF_JA: -+ op_jmp = true; -+ break; -+ default: -+ // XXX: assume this is a jcond op -+ op_jcond = true; -+ r_src0 = true; -+ if (stmt.code & BPF_X) -+ r_src1 = true; -+ else -+ i_src1 = true; -+ } -+ -+ // compute jump condition c -+ switch (BPF_OP (stmt.code)) -+ { -+ case BPF_JEQ: c = EQ; break; -+ case BPF_JNE: c = NE; break; -+ case BPF_JGT: c = GTU; break; -+ case BPF_JGE: c = GEU; break; -+ case BPF_JLT: c = LTU; break; -+ case BPF_JLE: c = LEU; break; -+ case BPF_JSGT: c = GT; break; -+ case BPF_JSGE: c = GE; break; -+ case BPF_JSLT: c = LT; break; -+ case BPF_JSLE: c = LE; break; -+ case BPF_JSET: c = TEST; break; -+ default: -+ if (op_jcond) -+ throw SEMANTIC_ERROR (_("invalid branch in bpf code"), stmt.tok); -+ } -+ break; -+ -+ default: -+ if (stmt.code == BPF_LD_MAP) -+ r_dest = true, i_src1 = true; -+ else -+ throw SEMANTIC_ERROR (_F("unknown opcode '%d' in bpf code", -+ stmt.code), stmt.tok); -+ } - -- std::istringstream ii (strip); -- ii >> std::setbase(0); -+ value *v_dest = NULL; -+ if (r_dest || r_src0) -+ v_dest = emit_asm_reg(stmt, stmt.dest); -+ else if (stmt.dest != "0" && stmt.dest != "-") -+ throw SEMANTIC_ERROR (_F("invalid register field '%s' in bpf code", -+ stmt.dest.c_str()), stmt.tok); - -- while (true) -+ value *v_src1 = NULL; -+ if (r_src1) -+ v_src1 = emit_asm_reg(stmt, stmt.src1); -+ else - { -- unsigned code; -- char s1, s2, s3, s4; -- char dest_b[256], src1_b[256]; -- int64_t off, imm; -+ if (stmt.src1 != "0" && stmt.src1 != "-") -+ throw SEMANTIC_ERROR (_F("invalid register field '%s' in bpf code", -+ stmt.src1.c_str()), stmt.tok); -+ if (i_src1) -+ v_src1 = this_prog.new_imm(stmt.imm); -+ else if (stmt.imm != 0) -+ throw SEMANTIC_ERROR (_("invalid immediate field in bpf code"), stmt.tok); -+ } - -- ii >> code >> s1; -- ii.get(dest_b, sizeof(dest_b), ',') >> s2; -- ii.get(src1_b, sizeof(src1_b), ',') >> s3; -- ii >> off >> s4 >> imm; -+ if (stmt.off != (int16_t)stmt.off) -+ throw SEMANTIC_ERROR (_F("offset field '%ld' out of range in bpf code", stmt.off), stmt.tok); - -- if (ii.fail() || s1 != ',' || s2 != ',' || s3 != ',' || s4 != ',') -- throw SEMANTIC_ERROR (_("invalid bpf embeddedcode syntax"), s->tok); -+ if (op_jmp) -+ { -+ block *target = label_map[stmt.jmp_target]; -+ this_prog.mk_jmp(this_ins, target); -+ } -+ else if (op_jcond) -+ { -+ if (label_map.count(stmt.jmp_target) == 0) -+ throw SEMANTIC_ERROR(_F("undefined jump target '%s' in bpf code", -+ stmt.jmp_target.c_str()), stmt.tok); -+ if (label_map.count(stmt.fallthrough) == 0) -+ throw SEMANTIC_ERROR(_F("BUG: undefined fallthrough target '%s'", -+ stmt.fallthrough.c_str()), stmt.tok); -+ block *target = label_map[stmt.jmp_target]; -+ block *fallthrough = label_map[stmt.fallthrough]; -+ this_prog.mk_jcond(this_ins, c, v_dest, v_src1, target, fallthrough); -+ } -+ else // regular opcode -+ { -+ insn *i = this_ins.new_insn(); -+ i->code = stmt.code; -+ i->dest = (r_dest ? v_dest : NULL); -+ i->src0 = (r_src0 ? v_dest : NULL); -+ i->src1 = v_src1; -+ i->off = stmt.off; -+ } -+} - -- if (code > 0xff && code != BPF_LD_MAP) -- throw SEMANTIC_ERROR (_("invalid bpf code"), s->tok); -+void -+bpf_unparser::visit_embeddedcode (embeddedcode *s) -+{ -+ std::vector statements; -+ asm_stmt stmt; - -- bool r_dest = false, r_src0 = false, r_src1 = false, i_src1 = false; -- switch (BPF_CLASS (code)) -- { -- case BPF_LDX: -- r_dest = r_src1 = true; -- break; -- case BPF_STX: -- r_src0 = r_src1 = true; -- break; -- case BPF_ST: -- r_src0 = i_src1 = true; -- break; -+ size_t pos = 0; -+ while ((pos = parse_asm_stmt(s, pos, stmt)) != std::string::npos) -+ { -+ statements.push_back(stmt); -+ } - -- case BPF_ALU: -- case BPF_ALU64: -- r_dest = true; -- if (code & BPF_X) -- r_src1 = true; -- else -- i_src1 = true; -- switch (BPF_OP (code)) -- { -- case BPF_NEG: -- case BPF_MOV: -- break; -- case BPF_END: -- /* X/K bit repurposed as LE/BE. */ -- i_src1 = false, r_src1 = true; -- break; -- default: -- r_src0 = true; -- } -- break; -+ // build basic block table -+ std::map label_map; -+ block *entry_block = this_ins.b; -+ label_map[";;entry"] = entry_block; - -- case BPF_JMP: -- switch (BPF_OP (code)) -- { -- case BPF_EXIT: -- break; -- case BPF_CALL: -- i_src1 = true; -- break; -- default: -- throw SEMANTIC_ERROR (_("invalid branch in bpf code"), s->tok); -- } -- break; -+ bool after_label = true; -+ asm_stmt *after_jump = NULL; -+ unsigned fallthrough_count = 0; -+ for (std::vector::iterator it = statements.begin(); -+ it != statements.end(); it++) -+ { -+ stmt = *it; - -- default: -- if (code == BPF_LD_MAP) -- r_dest = true, i_src1 = true; -- else -- throw SEMANTIC_ERROR (_("unknown opcode in bpf code"), s->tok); -- } -+ if (after_jump != NULL && stmt.kind == "label") -+ { -+ after_jump->fallthrough = stmt.dest; -+ } -+ else if (after_jump != NULL) -+ { -+ block *b = this_prog.new_block(); - -- std::string dest(dest_b); -- value *v_dest = NULL; -- if (r_dest || r_src0) -- v_dest = parse_reg(dest, s); -- else if (dest != "0") -- throw SEMANTIC_ERROR (_("invalid register field in bpf code"), s->tok); -- -- std::string src1(src1_b); -- value *v_src1 = NULL; -- if (r_src1) -- v_src1 = parse_reg(src1, s); -- else -- { -- if (src1 != "0") -- throw SEMANTIC_ERROR (_("invalid register field in bpf code"), s->tok); -- if (i_src1) -- v_src1 = this_prog.new_imm(imm); -- else if (imm != 0) -- throw SEMANTIC_ERROR (_("invalid immediate field in bpf code"), s->tok); -- } -+ // generate unique label for fallthrough edge -+ std::ostringstream oss; -+ oss << "fallthrough;;" << fallthrough_count++; -+ std::string fallthrough_label = oss.str(); -+ // XXX: semicolons prevent collision with programmer-defined labels - -- if (off != (int16_t)off) -- throw SEMANTIC_ERROR (_("offset field out of range in bpf code"), s->tok); -+ label_map[fallthrough_label] = b; -+ set_block(b); - -- insn *i = this_ins.new_insn(); -- i->code = code; -- i->dest = (r_dest ? v_dest : NULL); -- i->src0 = (r_src0 ? v_dest : NULL); -- i->src1 = v_src1; -- i->off = off; -+ after_jump->fallthrough = fallthrough_label; -+ } - -- ii >> s1; -- if (ii.eof()) -- break; -- if (s1 != ';') -- throw SEMANTIC_ERROR (_("invalid bpf embeddedcode syntax"), s->tok); -+ if (stmt.kind == "label" && after_label) -+ { -+ // avoid creating multiple blocks for consecutive labels -+ label_map[stmt.dest] = this_ins.b; -+ after_jump = NULL; -+ } -+ else if (stmt.kind == "label") -+ { -+ block *b = this_prog.new_block(); -+ label_map[stmt.dest] = b; -+ set_block(b); -+ after_label = true; -+ after_jump = NULL; -+ } -+ else if (stmt.has_fallthrough) -+ { -+ after_label = false; -+ after_jump = &*it; // be sure to refer to original, not copied stmt -+ } -+ else -+ { -+ after_label = false; -+ after_jump = NULL; -+ } -+ } -+ if (after_jump != NULL) // TODO: should just fall through to exit -+ throw SEMANTIC_ERROR (_("BUG: bpf embeddedcode doesn't support " -+ "fallthrough on final asm_stmt"), stmt.tok); -+ -+ // emit statements -+ bool jumped_already = true; -+ set_block(entry_block); -+ for (std::vector::iterator it = statements.begin(); -+ it != statements.end(); it++) -+ { -+ stmt = *it; -+ std::cerr << "DEBUG processing " << stmt << std::endl; // TODO -+ if (stmt.kind == "label") -+ { -+ // TODO: be sure there's no gap in the edge -+ if (!jumped_already) -+ emit_jmp (label_map[stmt.dest]); -+ set_block(label_map[stmt.dest]); -+ } -+ else if (stmt.kind == "opcode") -+ { -+ emit_asm_opcode (stmt, label_map); -+ } -+ else -+ throw SEMANTIC_ERROR (_F("BUG: bpf embeddedcode contains unexpected " -+ "asm_stmt kind '%s'", stmt.kind.c_str()), -+ stmt.tok); -+ jumped_already = stmt.has_fallthrough; -+ if (stmt.has_fallthrough) -+ set_block(label_map[stmt.fallthrough]); - } - } - -@@ -1016,8 +1461,13 @@ bpf_unparser::visit_delete_statement (delete_statement *s) - } - - // Translate string escape characters. -+// Accepts strings produced by parse.cxx lexer::scan and -+// by the eBPF embedded-code assembler. -+// -+// PR23559: This is currently an eBPF-only version of the function -+// that does not translate octal escapes. - std::string --translate_escapes (interned_string &str) -+translate_escapes (const interned_string &str) - { - std::string result; - bool saw_esc = false; -@@ -1045,16 +1495,21 @@ translate_escapes (interned_string &str) - return result; - } - -+value * -+bpf_unparser::emit_literal_string (const std::string &str, const token *tok) -+{ -+ size_t str_bytes = str.size() + 1; -+ if (str_bytes > BPF_MAXSTRINGLEN) -+ throw SEMANTIC_ERROR(_("string literal too long"), tok); -+ return this_prog.new_str(str); // will be lowered to a pointer by bpf-opt.cxx -+} -+ - void - bpf_unparser::visit_literal_string (literal_string* e) - { - interned_string v = e->value; - std::string str = translate_escapes(v); -- -- size_t str_bytes = str.size() + 1; -- if (str_bytes > BPF_MAXSTRINGLEN) -- throw SEMANTIC_ERROR(_("String literal too long"), e->tok); -- result = this_prog.new_str(str); // will be lowered to a pointer by bpf-opt.cxx -+ result = emit_literal_string(str, e->tok); - } - - void -@@ -1783,7 +2238,7 @@ bpf_unparser::visit_target_register (target_register* e) - // ??? Could use 8-byte chunks if we're starved for instruction count. - // ??? Endianness of the target comes into play here. - value * --emit_literal_str(program &this_prog, insn_inserter &this_ins, -+emit_simple_literal_str(program &this_prog, insn_inserter &this_ins, - value *dest, int ofs, std::string &src, bool zero_pad) - { - size_t str_bytes = src.size() + 1; -@@ -1835,15 +2290,15 @@ emit_literal_str(program &this_prog, insn_inserter &this_ins, - // ??? Could use 8-byte chunks if we're starved for instruction count. - // ??? Endianness of the target may come into play here. - value * --bpf_unparser::emit_copied_str(value *dest, int ofs, value *src, bool zero_pad) -+bpf_unparser::emit_string_copy(value *dest, int ofs, value *src, bool zero_pad) - { - if (src->is_str()) - { - /* If src is a string literal, its exact length is known and - we can emit simpler, unconditional string copying code. */ - std::string str = src->str(); -- return emit_literal_str(this_prog, this_ins, -- dest, ofs, str, zero_pad); -+ return emit_simple_literal_str(this_prog, this_ins, -+ dest, ofs, str, zero_pad); - } - - size_t str_bytes = BPF_MAXSTRINGLEN; -@@ -1931,7 +2386,7 @@ bpf_unparser::emit_copied_str(value *dest, int ofs, value *src, bool zero_pad) - } - - // XXX: Zero-padding is only used under specific circumstances; -- // see the corresponding comment in emit_literal_str(). -+ // see the corresponding comment in emit_simple_literal_str(). - if (zero_pad) - { - for (unsigned i = 0; i < str_words; ++i) -@@ -1977,7 +2432,7 @@ void - bpf_unparser::emit_str_arg(value *arg, int ofs, value *str) - { - value *frame = this_prog.lookup_reg(BPF_REG_10); -- value *out = emit_copied_str(frame, ofs, str, true /* zero pad */); -+ value *out = emit_string_copy(frame, ofs, str, true /* zero pad */); - emit_mov(arg, out); - } - -diff --git a/parse.h b/parse.h -index 42b0bc5fd..96aef0394 100644 ---- a/parse.h -+++ b/parse.h -@@ -65,11 +65,25 @@ struct token - token_junk_type junk_type; - - std::string junk_message(systemtap_session& session) const; -+ -+ // Creates a new token with the same content but different coordinates. -+ // Can be used for exact error reporting *within* a token e.g. embedded-code. -+ token *adjust_location(const source_loc &adjusted_loc) const -+ { // TODO split from header -+ token *new_tok = new token; -+ new_tok->location = adjusted_loc; -+ new_tok->content = content; -+ new_tok->chain = chain; -+ new_tok->type = type; -+ new_tok->junk_type = junk_type; -+ return new_tok; -+ } - - friend class parser; - friend class lexer; - private: - void make_junk (token_junk_type); -+ - token(): chain(0), type(tok_junk), junk_type(tok_junk_unknown) {} - token(const token& other): - location(other.location), content(other.content), --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0003-stapbpf-assembler-WIP-2-testcases-no-driver-so-far.patch b/SOURCES/rhbz1643997.0003-stapbpf-assembler-WIP-2-testcases-no-driver-so-far.patch deleted file mode 100644 index bc386aa..0000000 --- a/SOURCES/rhbz1643997.0003-stapbpf-assembler-WIP-2-testcases-no-driver-so-far.patch +++ /dev/null @@ -1,115 +0,0 @@ -From df2e44cd4a35c0cbba528e1d5821d5cd14cb7a87 Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Mon, 1 Oct 2018 15:39:00 -0400 -Subject: [PATCH 03/32] stapbpf assembler WIP #2 :: testcases (no driver so - far) - ---- - testsuite/systemtap.bpf/asm_tests/branch.stp | 22 ++++++++++++++++++++++ - testsuite/systemtap.bpf/asm_tests/err_token.stp | 21 +++++++++++++++++++++ - testsuite/systemtap.bpf/asm_tests/leniency.stp | 17 +++++++++++++++++ - testsuite/systemtap.bpf/asm_tests/simple.stp | 11 +++++++++++ - 4 files changed, 71 insertions(+) - create mode 100644 testsuite/systemtap.bpf/asm_tests/branch.stp - create mode 100644 testsuite/systemtap.bpf/asm_tests/err_token.stp - create mode 100644 testsuite/systemtap.bpf/asm_tests/leniency.stp - create mode 100644 testsuite/systemtap.bpf/asm_tests/simple.stp - -diff --git a/testsuite/systemtap.bpf/asm_tests/branch.stp b/testsuite/systemtap.bpf/asm_tests/branch.stp -new file mode 100644 -index 000000000..aa22bf195 ---- /dev/null -+++ b/testsuite/systemtap.bpf/asm_tests/branch.stp -@@ -0,0 +1,22 @@ -+function foo:long (x:long) %{ /* bpf */ /* pure */ -+ /* if x <= 10 then 50 else 100 */ -+ 0xd5, $x, -, _bar, 10; /* jsle $x, 10, _bar */ -+ 0xb7, $$, -, -, 100; /* mov $$, 100 */ -+ 0x05, -, -, _done, -; /* ja _done; */ -+ label, _bar; -+ 0xb7, $$, -, -, 50; /* mov $$, 50 */ -+ label, _done; -+ /* 0xbf, $$, $$, -, -; /* dummy op */ -+%} -+ -+function bar:long (x:long) { -+ if (x <= 10) return 50 else return 100 -+} -+ -+probe begin { -+ printf("foo(1)=%d should be %d\n", foo(1), bar(1)) -+ printf("foo(8)=%d should be %d\n", foo(8), bar(8)) -+ printf("foo(15)=%d should be %d\n", foo(15), bar(15)) -+ exit() -+} -+ -diff --git a/testsuite/systemtap.bpf/asm_tests/err_token.stp b/testsuite/systemtap.bpf/asm_tests/err_token.stp -new file mode 100644 -index 000000000..b9f8bd866 ---- /dev/null -+++ b/testsuite/systemtap.bpf/asm_tests/err_token.stp -@@ -0,0 +1,21 @@ -+function foo:long (x:long) %{ /* bpf */ /* pure */ -+ /* if x <= 10 then 50 else 100 */ -+ 0xd5, $x, -, _bar, 10; /* jsle $x, 10, _bar */ -+ 0xb7, $$, -, -, 100; /* mov $$, 100 */ -+ florb, -, -, _done, -; /* TRIGGER ERROR */ -+ label, _bar; -+ 0xb7, $$, -, -, 50; /* mov $$, 50 */ -+ label, _done; -+ /* 0xbf, $$, $$, -, -; /* dummy op */ -+%} -+ -+function bar:long (x:long) { -+ if (x <= 10) return 50 else return 100 -+} -+ -+probe begin { -+ printf("foo(1)=%d should be %d\n", foo(1), bar(1)) -+ printf("foo(8)=%d should be %d\n", foo(8), bar(8)) -+ printf("foo(15)=%d should be %d\n", foo(15), bar(15)) -+ exit() -+} -diff --git a/testsuite/systemtap.bpf/asm_tests/leniency.stp b/testsuite/systemtap.bpf/asm_tests/leniency.stp -new file mode 100644 -index 000000000..939061158 ---- /dev/null -+++ b/testsuite/systemtap.bpf/asm_tests/leniency.stp -@@ -0,0 +1,17 @@ -+function foo:long (x:long) %{ /* bpf */ /* pure */ -+ /* if x < 10 then 17 else 16 */ -+ 0xa5, $x, -, _bar, 10; /* jlt $x, 10, _bar */ -+ 0xb7, $this is an "!!ide\nt!!" believe it or not, -, -, 16; /* mov $t, 0 */ -+ 0xbf, $$, $thisisan"!!ide\nt!!"believeitornot, -, -; /* mov $$, $t */ -+ 0x05, -, -, _done, -; /* ja _done; */ -+ label, _bar; -+ 0xb7, $$, -, -, 17; /* mov $$, 1 */ -+ label, _done; -+%} -+ -+probe begin { -+ printf("foo(1)=%d\n", foo(1)) -+ printf("foo(15)=%d\n", foo(15)) -+ exit() -+} -+ -diff --git a/testsuite/systemtap.bpf/asm_tests/simple.stp b/testsuite/systemtap.bpf/asm_tests/simple.stp -new file mode 100644 -index 000000000..693219d15 ---- /dev/null -+++ b/testsuite/systemtap.bpf/asm_tests/simple.stp -@@ -0,0 +1,11 @@ -+function foo:long (x:long) %{ /* bpf */ /* pure */ -+ /* compute 100-x */ -+ 0xb7, $$, -, -, 100; /* mov $$, ee */ -+ 0x1f, $$, $x, -, -; /* sub $$, $x */ -+%} -+ -+probe begin { -+ printf("foo(1)=%d\n", foo(1)) -+ printf("foo(15)=%d\n", foo(15)) -+ exit() -+} --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0004-stapbpf-assembler-WIP-3-additional-assembly-test-cas.patch b/SOURCES/rhbz1643997.0004-stapbpf-assembler-WIP-3-additional-assembly-test-cas.patch deleted file mode 100644 index 358d800..0000000 --- a/SOURCES/rhbz1643997.0004-stapbpf-assembler-WIP-3-additional-assembly-test-cas.patch +++ /dev/null @@ -1,128 +0,0 @@ -From 6411e53fe729a987a300274f6b15fd88b737367d Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Tue, 16 Oct 2018 18:13:47 -0400 -Subject: [PATCH 04/32] stapbpf assembler WIP #3 :: additional assembly test - cases - ---- - testsuite/systemtap.bpf/asm_tests/err_alloc.stp | 10 ++++++++++ - testsuite/systemtap.bpf/asm_tests/err_numeric.stp | 18 ++++++++++++++++++ - testsuite/systemtap.bpf/asm_tests/simple.stp | 6 +++--- - testsuite/systemtap.bpf/asm_tests/string.stp | 22 ++++++++++++++++++++++ - testsuite/systemtap.bpf/asm_tests/temporary.stp | 14 ++++++++++++++ - 5 files changed, 67 insertions(+), 3 deletions(-) - create mode 100644 testsuite/systemtap.bpf/asm_tests/err_alloc.stp - create mode 100644 testsuite/systemtap.bpf/asm_tests/err_numeric.stp - create mode 100644 testsuite/systemtap.bpf/asm_tests/string.stp - create mode 100644 testsuite/systemtap.bpf/asm_tests/temporary.stp - -diff --git a/testsuite/systemtap.bpf/asm_tests/err_alloc.stp b/testsuite/systemtap.bpf/asm_tests/err_alloc.stp -new file mode 100644 -index 000000000..6778a52e2 ---- /dev/null -+++ b/testsuite/systemtap.bpf/asm_tests/err_alloc.stp -@@ -0,0 +1,10 @@ -+function foo:long (x:long) %{ /* bpf */ /* pure */ -+ alloc "not a register", BPF_MAXSTRINGLEN; /* SHOULD ERROR */ -+ 0xbf, $$, "fifty", -, -; /* mov $$, "fifty" */ -+%} -+ -+ -+probe begin { -+ printf("foo(1)=%d should be fifty\n", foo(1)) -+ exit() -+} -diff --git a/testsuite/systemtap.bpf/asm_tests/err_numeric.stp b/testsuite/systemtap.bpf/asm_tests/err_numeric.stp -new file mode 100644 -index 000000000..9428e5704 ---- /dev/null -+++ b/testsuite/systemtap.bpf/asm_tests/err_numeric.stp -@@ -0,0 +1,18 @@ -+function foo:long (x:long) %{ /* bpf */ /* pure */ -+ /* verify refusal to accept gibberish */ -+ 0xd33333333333333333333333333333333333333333333333333333333333333333333333333334db33f, $x, -, _bar, 10; /* XTREAM opcode */ -+ /* 0xb7, $$, -, huirgishvirguwishgiburg, 100; /* XTREAM 3rd arg */ -+ /* 0xb7, $$, -, -, borkborkborkborkbork; /* XTREAM 4th arg */ -+%} -+ -+function bar:long (x:long) { -+ if (x <= 10) return 50 else return 100 -+} -+ -+probe begin { -+ printf("foo(1)=%d should be %d\n", foo(1), bar(1)) -+ printf("foo(8)=%d should be %d\n", foo(8), bar(8)) -+ printf("foo(15)=%d should be %d\n", foo(15), bar(15)) -+ exit() -+} -+ -diff --git a/testsuite/systemtap.bpf/asm_tests/simple.stp b/testsuite/systemtap.bpf/asm_tests/simple.stp -index 693219d15..17184a139 100644 ---- a/testsuite/systemtap.bpf/asm_tests/simple.stp -+++ b/testsuite/systemtap.bpf/asm_tests/simple.stp -@@ -1,11 +1,11 @@ - function foo:long (x:long) %{ /* bpf */ /* pure */ - /* compute 100-x */ -- 0xb7, $$, -, -, 100; /* mov $$, ee */ -+ 0xb7, $$, -, -, 100; /* mov $$, 100 */ - 0x1f, $$, $x, -, -; /* sub $$, $x */ - %} - - probe begin { -- printf("foo(1)=%d\n", foo(1)) -- printf("foo(15)=%d\n", foo(15)) -+ printf("foo(1)=%d, should be 99\n", foo(1)) -+ printf("foo(15)=%d, should be 85\n", foo(15)) - exit() - } -diff --git a/testsuite/systemtap.bpf/asm_tests/string.stp b/testsuite/systemtap.bpf/asm_tests/string.stp -new file mode 100644 -index 000000000..dce665c14 ---- /dev/null -+++ b/testsuite/systemtap.bpf/asm_tests/string.stp -@@ -0,0 +1,22 @@ -+function foo:long (x:long) %{ /* bpf */ /* pure */ -+ /* if x <= 10 then "fifty" else "one-hundred" */ -+ 0xd5, $x, -, _bar, 10; /* jsle $x, 10, _bar */ -+ 0xbf, $$, "one-hundred", -, -; /* mov $$, "one-hundred" */ -+ 0x05, -, -, _done, -; /* ja _done; */ -+ label, _bar; -+ 0xbf, $$, "fifty", -, -; /* mov $$, "fifty" */ -+ label, _done; -+ /* 0xbf, $$, $$, -, -; /* dummy op */ -+%} -+ -+function bar:long (x:long) { -+ if (x <= 10) return 50 else return 100 -+} -+ -+probe begin { -+ printf("foo(1)=%d should be %d\n", foo(1), bar(1)) -+ printf("foo(8)=%d should be %d\n", foo(8), bar(8)) -+ printf("foo(15)=%d should be %d\n", foo(15), bar(15)) -+ exit() -+} -+ -diff --git a/testsuite/systemtap.bpf/asm_tests/temporary.stp b/testsuite/systemtap.bpf/asm_tests/temporary.stp -new file mode 100644 -index 000000000..153c759ba ---- /dev/null -+++ b/testsuite/systemtap.bpf/asm_tests/temporary.stp -@@ -0,0 +1,14 @@ -+function foo:long (x:long) %{ /* bpf */ /* pure */ -+ /* compute (100-x)*(x+2) */ -+ 0xb7, $$, -, -, 100; /* mov $$, 100 */ -+ 0x1f, $$, $x, -, -; /* sub $$, $x */ -+ 0xbf, $tmp, $x, -, -; /* mov $tmp, $x */ -+ 0x07, $tmp, -, -, 2; /* add $tmp, 2 */ -+ 0x2f, $$, $tmp, -, -; /* mul $$, $tmp */ -+%} -+ -+probe begin { -+ printf("foo(1)=%d, should be 99*3=297\n", foo(1)) -+ printf("foo(15)=%d, should be 85*18=1530\n", foo(15)) -+ exit() -+} --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0005-stapbpf-assembler-WIP-4-alloc-and-helper-call-operat.patch b/SOURCES/rhbz1643997.0005-stapbpf-assembler-WIP-4-alloc-and-helper-call-operat.patch deleted file mode 100644 index c4c1c97..0000000 --- a/SOURCES/rhbz1643997.0005-stapbpf-assembler-WIP-4-alloc-and-helper-call-operat.patch +++ /dev/null @@ -1,604 +0,0 @@ -From f2339483ab00eff7a1a45c33b968891a63668c98 Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Tue, 16 Oct 2018 18:16:48 -0400 -Subject: [PATCH 05/32] stapbpf assembler WIP #4 :: alloc and (helper) call - operations - ---- - bpf-base.cxx | 46 ++++++---- - bpf-internal.h | 8 +- - bpf-translate.cxx | 259 ++++++++++++++++++++++++++++++++++++++++------------- - tapset/logging.stp | 2 + - 4 files changed, 237 insertions(+), 78 deletions(-) - -diff --git a/bpf-base.cxx b/bpf-base.cxx -index c3e36efa1..277927b72 100644 ---- a/bpf-base.cxx -+++ b/bpf-base.cxx -@@ -135,31 +135,43 @@ is_commutative(opcode code) - } - } - -+/* Various functions for eBPF helper lookup: */ -+ -+std::map bpf_func_name_map; -+std::map bpf_func_id_map; -+ -+void -+init_bpf_helper_tables () // TODO call before script translation -+{ -+#define __BPF_SET_FUNC_NAME(x) bpf_func_name_map[BPF_FUNC_ ## x] = #x -+#define __BPF_SET_FUNC_ID(x) bpf_func_id_map[#x] = BPF_FUNC_ ## x -+ __BPF_FUNC_MAPPER(__BPF_SET_FUNC_NAME) -+ __STAPBPF_FUNC_MAPPER(__BPF_SET_FUNC_NAME) -+ __BPF_FUNC_MAPPER(__BPF_SET_FUNC_ID) -+ __STAPBPF_FUNC_MAPPER(__BPF_SET_FUNC_ID) -+ (void)0; -+} -+ - const char * - bpf_function_name (unsigned id) - { -- switch (id) -- { -- case BPF_FUNC_map_lookup_elem: return "map_lookup_elem"; -- case BPF_FUNC_map_update_elem: return "map_update_elem"; -- case BPF_FUNC_map_delete_elem: return "map_delete_elem"; -- case BPF_FUNC_probe_read: return "probe_read"; -- case BPF_FUNC_ktime_get_ns: return "ktime_get_ns"; -- case BPF_FUNC_trace_printk: return "trace_printk"; -- case BPF_FUNC_get_prandom_u32: return "get_prandom_u32"; -- case BPF_FUNC_get_smp_processor_id: return "get_smp_processor_id"; -- case BPF_FUNC_get_current_pid_tgid: return "get_current_pid_tgid"; -- case BPF_FUNC_get_current_uid_gid: return "get_current_uid_gid"; -- case BPF_FUNC_get_current_comm: return "get_current_comm"; -- case BPF_FUNC_perf_event_read: return "perf_event_read"; -- case BPF_FUNC_perf_event_output: return "perf_event_output"; -- default: return NULL; -- } -+ if (bpf_func_name_map.count(id) != 0) -+ return bpf_func_name_map[id]; -+ return NULL; -+} -+ -+bpf_func_id -+bpf_function_id (const std::string& name) -+{ -+ if (bpf_func_id_map.count(name) != 0) -+ return bpf_func_id_map[name]; -+ return __BPF_FUNC_MAX_ID; - } - - unsigned - bpf_function_nargs (unsigned id) - { -+ // ??? generalize to all bpf functions - switch (id) - { - case BPF_FUNC_map_lookup_elem: return 2; -diff --git a/bpf-internal.h b/bpf-internal.h -index 719446db8..61514db9f 100644 ---- a/bpf-internal.h -+++ b/bpf-internal.h -@@ -96,14 +96,20 @@ bool is_move(opcode c); - bool is_ldst(opcode c); - bool is_binary(opcode c); - bool is_commutative(opcode c); -+ -+void init_bpf_helper_tables(); - const char *bpf_function_name (unsigned id); -+bpf_func_id bpf_function_id (const std::string &name); - unsigned bpf_function_nargs (unsigned id); - - const opcode BPF_LD_MAP = BPF_LD | BPF_IMM | BPF_DW | (BPF_PSEUDO_MAP_FD << 8); - --// Not actual BPF helpers, but treating them like one simplifies some of the -+// Not actual BPF helpers, but treating them as such simplifies some of the - // interpreter logic. We give them IDs that shouldn't conflict with IDs of - // real BPF helpers. -+#define __STAPBPF_FUNC_MAPPER(FN) \ -+ FN(map_get_next_key), \ -+ FN(sprintf), - const bpf_func_id BPF_FUNC_map_get_next_key = (bpf_func_id) -1; - const bpf_func_id BPF_FUNC_sprintf = (bpf_func_id) -2; - -diff --git a/bpf-translate.cxx b/bpf-translate.cxx -index 023ac6ce7..af3f54b50 100644 ---- a/bpf-translate.cxx -+++ b/bpf-translate.cxx -@@ -179,7 +179,7 @@ struct bpf_unparser : public throwing_visitor - // TODO General triage of bpf-possible functionality: - virtual void visit_block (::block *s); - // TODO visit_try_block -> UNHANDLED -- virtual void visit_embeddedcode (embeddedcode *s); // TODO need to find testcase/example for this -+ virtual void visit_embeddedcode (embeddedcode *s); - virtual void visit_null_statement (null_statement *s); - virtual void visit_expr_statement (expr_statement *s); - virtual void visit_if_statement (if_statement* s); -@@ -192,7 +192,7 @@ struct bpf_unparser : public throwing_visitor - virtual void visit_continue_statement (continue_statement* s); - virtual void visit_literal_string (literal_string *e); - virtual void visit_literal_number (literal_number* e); -- // TODO visit_embedded_expr -> UNHANDLED, could be handled like embedded_code with a return value? -+ // TODO visit_embedded_expr -> UNHANDLED, could treat as embedded_code - virtual void visit_binary_expression (binary_expression* e); - virtual void visit_unary_expression (unary_expression* e); - virtual void visit_pre_crement (pre_crement* e); -@@ -200,7 +200,7 @@ struct bpf_unparser : public throwing_visitor - virtual void visit_logical_or_expr (logical_or_expr* e); - virtual void visit_logical_and_expr (logical_and_expr* e); - virtual void visit_array_in (array_in* e); -- // ??? visit_regex_query is UNHANDLED, requires adding new kernel functionality. -+ // ??? visit_regex_query -> UNHANDLED, requires new kernel functionality - virtual void visit_compound_expression (compound_expression *e); - virtual void visit_comparison (comparison* e); - // TODO visit_concatenation -> (2) pseudo-LOOP: copy the strings while concatenating -@@ -239,14 +239,21 @@ struct bpf_unparser : public throwing_visitor - value *emit_context_var(bpf_context_vardecl *v); - - // Used for the embedded-code assembler: -+ int64_t parse_imm (const asm_stmt &stmt, const std::string &str); - size_t parse_asm_stmt (embeddedcode *s, size_t start, - /*OUT*/asm_stmt &stmt); -- value *emit_asm_arg(const asm_stmt &stmt, const std::string ®, -- bool allow_imm = true); -+ value *emit_asm_arg(const asm_stmt &stmt, const std::string &arg, -+ bool allow_imm = true, bool allow_emit = true); - value *emit_asm_reg(const asm_stmt &stmt, const std::string ®); -+ value *get_asm_reg(const asm_stmt &stmt, const std::string ®); - void emit_asm_opcode(const asm_stmt &stmt, - std::map label_map); - -+ // Used for the embedded-code assembler's diagnostics: -+ source_loc adjusted_loc; -+ size_t adjust_pos; -+ std::vector adjusted_toks; // track for deallocation -+ - // Used for string data: - value *emit_literal_string(const std::string &str, const token *tok); - value *emit_string_copy(value *dest, int ofs, value *src, bool zero_pad = false); -@@ -580,17 +587,22 @@ bpf_unparser::visit_block (::block *s) - - Ahh for the days of 1960s FORTRAN. - -- TODO: It might make more sense to implement an assembler based on -+ ??? It might make more sense to implement an assembler based on - the syntax used in official eBPF subsystem docs. */ - --/* Possible assembly statement types include: -+/* Supported assembly statement types include: - - ::= label, ; -+ ::= alloc, , ; -+ ::= call, , , , ...; -+ ::= printf, , , ...; -+ ::= error, , , ...; - ::= , , , - , ; - -- Possible argument types include: -+ Supported argument types include: - -+ ::= | - ::= | r | - $ | $ | $$ | - ::= | BPF_MAXSTRINGLEN -@@ -598,6 +610,9 @@ bpf_unparser::visit_block (::block *s) - - */ - -+// TODO -+#define BPF_ASM_DEBUG -+ - struct asm_stmt { - std::string kind; - -@@ -609,9 +624,10 @@ struct asm_stmt { - bool has_fallthrough = false; - std::string jmp_target, fallthrough; - -+ // metadata for call, error instructions -+ std::vector params; -+ - token *tok; -- bool deallocate_tok = false; -- ~asm_stmt() { if (deallocate_tok) delete tok; } - }; - - std::ostream& -@@ -647,10 +663,30 @@ is_numeric (const std::string &str) - stol(str, &pos, 0); - } catch (std::invalid_argument &e) { - return false; -+ } catch (std::out_of_range &e) { -+ /* XXX: probably numeric but not valid; give up */ -+ return false; - } - return (pos == str.size()); - } - -+int64_t -+bpf_unparser::parse_imm (const asm_stmt &stmt, const std::string &str) -+{ -+ int64_t val; -+ if (str == "BPF_MAXSTRINGLEN") -+ val = BPF_MAXSTRINGLEN; -+ else if (str == "-") -+ val = 0; -+ else try { -+ val = stol(str); -+ } catch (std::exception &e) { // XXX: invalid_argument, out_of_range -+ throw SEMANTIC_ERROR (_F("invalid bpf embeddedcode operand '%s'", -+ str.c_str()), stmt.tok); -+ } -+ return val; -+} -+ - /* Parse an assembly statement starting from position start in code, - then write the output in stmt. Returns a position immediately after - the parsed statement. */ -@@ -663,31 +699,14 @@ bpf_unparser::parse_asm_stmt (embeddedcode *s, size_t start, - retry: - std::vector args; - unsigned n = code.size(); -+ size_t pos; - bool in_comment = false; - bool in_string = false; - -- // compute token with adjusted source location for diagnostics -- source_loc adjusted_loc; // TODO: ought to create a proper copy constructor for source_loc -- adjusted_loc.file = s->tok->location.file; -- adjusted_loc.line = s->tok->location.line; -- adjusted_loc.column = s->tok->location.column; -- for (size_t pos = 0; pos < start && pos < n; pos++) -- { -- // TODO: should save adjusted_loc state between parse_asm_stmt invocations; add field? -- char c = code[pos]; -- if (c == '\n') -- { -- adjusted_loc.line++; -- adjusted_loc.column = 1; -- } -- else -- adjusted_loc.column++; -- } -- -- // TODO: As before, parser is extremely non-rigorous and could do -+ // ??? As before, parser is extremely non-rigorous and could do - // with some tightening in terms of the inputs it accepts. -- size_t pos; - std::string arg = ""; -+ size_t save_start = start; // -- position for diagnostics - for (pos = start; pos < n; pos++) - { - char c = code[pos]; -@@ -714,6 +733,9 @@ bpf_unparser::parse_asm_stmt (embeddedcode *s, size_t start, - ++pos, in_comment = true; - else if (c == '"') // found a literal string - { -+ if (arg.empty() && args.empty()) -+ save_start = pos; // start of first argument -+ - // XXX: This allows '"' inside an arg and will treat the - // string as a sequence of weird identifier characters. A - // more rigorous parser would error on mixing strings and -@@ -738,6 +760,9 @@ bpf_unparser::parse_asm_stmt (embeddedcode *s, size_t start, - } - else // found (we assume) a regular char - { -+ if (arg.empty() && args.empty()) -+ save_start = pos; // start of first argument -+ - // XXX: As before, this strips whitespace within args - // (so '$ab', '$ a b' and '$a b' are equivalent). - // -@@ -760,28 +785,73 @@ bpf_unparser::parse_asm_stmt (embeddedcode *s, size_t start, - goto retry; - } - -+ // compute token with adjusted source location for diagnostics -+ // TODO: needs some attention to how multiline tokens are printed in error reporting -- with this code, caret aligns incorrectly -+ for (/* use saved adjust_pos */; adjust_pos < save_start && adjust_pos < n; adjust_pos++) -+ { -+ char c = code[adjust_pos]; -+ if (c == '\n') -+ { -+ adjusted_loc.line++; -+ adjusted_loc.column = 1; -+ } -+ else -+ adjusted_loc.column++; -+ } -+ - // set token with adjusted source location -- //stmt.tok = (token *)s->tok; -- // TODO this segfaults for some reason, some data not copied? - stmt.tok = s->tok->adjust_location(adjusted_loc); -- stmt.deallocate_tok = false; // TODO must avoid destroy-on-copy -+ adjusted_toks.push_back(stmt.tok); - -- std::cerr << "DEBUG GOT stmt "; // TODO -- for (unsigned k = 0; k < args.size(); k++) std::cerr << args[k] << " / "; -- std::cerr << std::endl; // TODO -+#ifdef BPF_ASM_DEBUG -+ std::cerr << "bpf_asm parse_asm_stmt: tokenizer got "; -+ for (unsigned k = 0; k < args.size(); k++) -+ std::cerr << args[k] << ", "; -+ std::cerr << std::endl; -+#endif - if (args[0] == "label") - { - if (args.size() != 2) -- throw SEMANTIC_ERROR (_("invalid bpf embeddedcode syntax"), stmt.tok); -+ throw SEMANTIC_ERROR (_F("invalid bpf embeddedcode syntax (label expects 1 arg, found %lu)", args.size()-1), stmt.tok); -+ stmt.kind = args[0]; -+ stmt.dest = args[1]; -+ } -+ else if (args[0] == "alloc") -+ { -+ if (args.size() != 3) -+ throw SEMANTIC_ERROR (_F("invalid bpf embeddedcode syntax (alloc expects 2 args, found %lu)", args.size()-1), stmt.tok); - stmt.kind = args[0]; - stmt.dest = args[1]; -+ stmt.imm = parse_imm(stmt, args[2]); -+ } -+ else if (args[0] == "call") -+ { -+ if (args.size() < 3) -+ throw SEMANTIC_ERROR (_F("invalid bpf embeddedcode syntax (call expects at least 2 args, found %lu)", args.size()-1), stmt.tok); -+ stmt.kind = args[0]; -+ stmt.dest = args[1]; -+ for (unsigned k = 2; k < args.size(); k++) -+ stmt.params.push_back(args[k]); -+ } -+ else if (args[0] == "printf" || args[0] == "error") -+ { -+ if (args.size() < 2) -+ throw SEMANTIC_ERROR (_F("invalid bpf embeddedcode syntax (%s expects at least 2 args, found %lu)", args[0].c_str(), args.size()-1), stmt.tok); -+ stmt.kind = args[0]; -+ for (unsigned k = 2; k < args.size(); k++) -+ stmt.params.push_back(args[k]); - } - else if (is_numeric(args[0])) - { -- if (args.size() != 5) // TODO change to 4 to test err+tok -- throw SEMANTIC_ERROR (_("invalid bpf embeddedcode syntax"), stmt.tok); -+ if (args.size() != 5) -+ throw SEMANTIC_ERROR (_F("invalid bpf embeddedcode syntax (opcode expects 4 args, found %lu)", args.size()-1), stmt.tok); - stmt.kind = "opcode"; -- stmt.code = stoul(args[0], 0, 0); // TODO signal error -+ try { -+ stmt.code = stoul(args[0], 0, 0); -+ } catch (std::exception &e) { // XXX: invalid_argument, out_of_range -+ throw SEMANTIC_ERROR (_F("invalid bpf embeddedcode opcode '%s'", -+ args[0].c_str()), stmt.tok); -+ } - stmt.dest = args[1]; - stmt.src1 = args[2]; - -@@ -799,25 +869,16 @@ bpf_unparser::parse_asm_stmt (embeddedcode *s, size_t start, - stmt.off = 0; - stmt.jmp_target = args[3]; - } -- else if (args[3] == "BPF_MAXSTRINGLEN") -- stmt.off = BPF_MAXSTRINGLEN; -- else if (args[3] == "-") -- stmt.off = 0; - else -- stmt.off = stol(args[3]); // TODO signal error -+ stmt.off = parse_imm(stmt, args[3]); - -- if (args[4] == "BPF_MAXSTRINGLEN") -- stmt.imm = BPF_MAXSTRINGLEN; -- else if (args[4] == "-") -- stmt.imm = 0; -- else -- stmt.imm = stol(args[4]); // TODO signal error -+ stmt.imm = parse_imm(stmt, args[4]); - } - else - throw SEMANTIC_ERROR (_F("unknown bpf embeddedcode operator '%s'", - args[0].c_str()), stmt.tok); - -- // we returned a statement, so there's more parsing to be done -+ // we returned one statement, there may be more parsing to be done - return pos; - } - -@@ -828,7 +889,7 @@ std::string translate_escapes (const interned_string &str); - May emit code to store a string constant on the stack. */ - value * - bpf_unparser::emit_asm_arg (const asm_stmt &stmt, const std::string &arg, -- bool allow_imm) -+ bool allow_imm, bool allow_emit) - { - if (arg == "$$") - { -@@ -859,7 +920,6 @@ bpf_unparser::emit_asm_arg (const asm_stmt &stmt, const std::string &arg, - auto ok = this_locals->insert (v); - assert (ok.second); - return reg; -- // TODO write a testcase - } - else if (is_numeric(arg) && allow_imm) - { -@@ -879,13 +939,17 @@ bpf_unparser::emit_asm_arg (const asm_stmt &stmt, const std::string &arg, - } - else if (arg[0] == '"') - { -- // TODO verify correctness -+ if (!allow_emit) -+ throw SEMANTIC_ERROR (_F("invalid bpf argument %s " -+ "(string literal not allowed here)", -+ arg.c_str()), stmt.tok); -+ - /* arg is a string constant */ - if (arg[arg.size() - 1] != '"') - throw SEMANTIC_ERROR (_F("BUG: improper string %s", - arg.c_str()), stmt.tok); - std::string escaped_str = arg.substr(1,arg.size()-2); /* strip quotes */ -- std::string str = translate_escapes(escaped_str); // TODO interned_str? -+ std::string str = translate_escapes(escaped_str); - return emit_literal_string(str, stmt.tok); - } - else if (arg == "BPF_MAXSTRINGLEN") -@@ -913,12 +977,22 @@ bpf_unparser::emit_asm_arg (const asm_stmt &stmt, const std::string &arg, - - } - -+/* As above, but don't accept immediate values. -+ Do accept string constants (since they're stored in a register). */ - value * - bpf_unparser::emit_asm_reg (const asm_stmt &stmt, const std::string ®) - { - return emit_asm_arg(stmt, reg, /*allow_imm=*/false); - } - -+/* As above, but don't allow string constants or anything that emits code. -+ Useful if the context requires an lvalue. */ -+value * -+bpf_unparser::get_asm_reg (const asm_stmt &stmt, const std::string ®) -+{ -+ return emit_asm_arg(stmt, reg, /*allow_imm=*/false, /*allow_emit=*/false); -+} -+ - void - bpf_unparser::emit_asm_opcode (const asm_stmt &stmt, - std::map label_map) -@@ -1013,7 +1087,7 @@ bpf_unparser::emit_asm_opcode (const asm_stmt &stmt, - - value *v_dest = NULL; - if (r_dest || r_src0) -- v_dest = emit_asm_reg(stmt, stmt.dest); -+ v_dest = get_asm_reg(stmt, stmt.dest); - else if (stmt.dest != "0" && stmt.dest != "-") - throw SEMANTIC_ERROR (_F("invalid register field '%s' in bpf code", - stmt.dest.c_str()), stmt.tok); -@@ -1069,6 +1143,10 @@ bpf_unparser::visit_embeddedcode (embeddedcode *s) - std::vector statements; - asm_stmt stmt; - -+ // track adjusted source location for each stmt -+ adjusted_loc = s->tok->location; -+ adjust_pos = 0; -+ - size_t pos = 0; - while ((pos = parse_asm_stmt(s, pos, stmt)) != std::string::npos) - { -@@ -1133,7 +1211,7 @@ bpf_unparser::visit_embeddedcode (embeddedcode *s) - after_jump = NULL; - } - } -- if (after_jump != NULL) // TODO: should just fall through to exit -+ if (after_jump != NULL) // ??? should just fall through to exit - throw SEMANTIC_ERROR (_("BUG: bpf embeddedcode doesn't support " - "fallthrough on final asm_stmt"), stmt.tok); - -@@ -1144,14 +1222,67 @@ bpf_unparser::visit_embeddedcode (embeddedcode *s) - it != statements.end(); it++) - { - stmt = *it; -- std::cerr << "DEBUG processing " << stmt << std::endl; // TODO -+#ifdef BPF_ASM_DEBUG -+ std::cerr << "bpf_asm visit_embeddedcode: " << stmt << std::endl; -+#endif - if (stmt.kind == "label") - { -- // TODO: be sure there's no gap in the edge - if (!jumped_already) - emit_jmp (label_map[stmt.dest]); - set_block(label_map[stmt.dest]); - } -+ else if (stmt.kind == "alloc") -+ { -+ /* Reserve stack space and store its address in dest. */ -+ int ofs = this_prog.max_tmp_space + stmt.imm; -+ value *dest = get_asm_reg(stmt, stmt.dest); -+ this_prog.use_tmp_space(-ofs); -+ this_prog.mk_binary(this_ins, BPF_ADD, dest, -+ this_prog.lookup_reg(BPF_REG_10) /*frame*/, -+ this_prog.new_imm(ofs)); -+ } -+ else if (stmt.kind == "call") -+ { -+ std::string func_name = stmt.params[0]; -+ bpf_func_id hid = bpf_function_id(func_name); -+ if (hid != __BPF_FUNC_MAX_ID) -+ { -+ // TODO diagnostic: check if the number of arguments is correct -+ regno r = BPF_REG_1; unsigned nargs = 0; -+ for (unsigned k = 1; k < stmt.params.size(); k++) -+ { -+ // ??? Could make params optional to avoid this part, -+ // ??? since the calling convention is well-known. -+ value *from_reg = emit_asm_arg(stmt, stmt.params[k]); -+ value *to_reg = this_prog.lookup_reg(r); -+ this_prog.mk_mov(this_ins, to_reg, from_reg); -+ nargs++; r++; -+ } -+ this_prog.mk_call(this_ins, hid, nargs); -+ this_prog.mk_mov(this_ins, get_asm_reg(stmt, stmt.dest), -+ this_prog.lookup_reg(BPF_REG_0) /* returnval */); -+ // ??? Could make stmt.dest optional to avoid this extra mov, -+ // ??? since the BPF_REG_0 convention is well-known. -+ } -+ else -+ { -+ // TODO function_name = params[0]; -+ // TODO args = parse_reg(params[1]), parse_reg(params[2]), ... -+ // TODO emit_functioncall() with good bits from visit_functioncall() -+ throw SEMANTIC_ERROR (_("BUG: bpf embeddedcode non-helper 'call' not yet supported"), -+ stmt.tok); -+ } -+ } -+ else if (stmt.kind == "printf" || stmt.kind == "error") -+ { -+ // TODO Note that error() should be modeled on the tapset function in tapset/logging.stp -+ // TODO format = params[0]; -+ // TODO args = parse_reg(params[1]), parse_reg(params[2]), ... -+ // TODO emit_print_format() with good bits from visit_print_format() -+ // TODO if (stmt.kind == "error") emit functioncall to exit() -+ throw SEMANTIC_ERROR (_("BUG: bpf embeddedcode 'printf/error' not yet supported"), -+ stmt.tok); -+ } - else if (stmt.kind == "opcode") - { - emit_asm_opcode (stmt, label_map); -@@ -1164,6 +1295,12 @@ bpf_unparser::visit_embeddedcode (embeddedcode *s) - if (stmt.has_fallthrough) - set_block(label_map[stmt.fallthrough]); - } -+ -+ // housekeeping -- deallocate adjusted_toks along with statements -+ for (std::vector::iterator it = adjusted_toks.begin(); -+ it != adjusted_toks.end(); it++) -+ delete *it; -+ adjusted_toks.clear(); - } - - void -@@ -3260,6 +3397,8 @@ translate_bpf_pass (systemtap_session& s) - { - using namespace bpf; - -+ init_bpf_helper_tables(); -+ - if (elf_version(EV_CURRENT) == EV_NONE) - return 1; - -diff --git a/tapset/logging.stp b/tapset/logging.stp -index 59edce3c8..839239b8f 100644 ---- a/tapset/logging.stp -+++ b/tapset/logging.stp -@@ -128,6 +128,8 @@ function error (msg:string) - exit() // TODO: should support MAXERRORS, probe error {} - } - %) -+// NOTE: The 'error' statement in the eBPF assembler in bpf-translate.cxx -+// should be kept up-to-date with the behaviour of this function. - - /** - * sfunction assert - evaluate assertion --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0006-stapbpf-assembler-WIP-5-basic-kernel_string-implemen.patch b/SOURCES/rhbz1643997.0006-stapbpf-assembler-WIP-5-basic-kernel_string-implemen.patch deleted file mode 100644 index c9959f7..0000000 --- a/SOURCES/rhbz1643997.0006-stapbpf-assembler-WIP-5-basic-kernel_string-implemen.patch +++ /dev/null @@ -1,128 +0,0 @@ -From f614583a605f4c23d2f6e1a2ad31e089d10f8d8e Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Tue, 16 Oct 2018 18:17:25 -0400 -Subject: [PATCH 06/32] stapbpf assembler WIP #5 :: basic kernel_string() - implementation - ---- - tapset/bpf/conversions.stp | 108 +++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 108 insertions(+) - create mode 100644 tapset/bpf/conversions.stp - -diff --git a/tapset/bpf/conversions.stp b/tapset/bpf/conversions.stp -new file mode 100644 -index 000000000..d741ec584 ---- /dev/null -+++ b/tapset/bpf/conversions.stp -@@ -0,0 +1,108 @@ -+// conversions tapset -- eBPF version -+// Copyright (C) 2018 Red Hat Inc. -+// -+// This file is part of systemtap, and is free software. You can -+// redistribute it and/or modify it under the terms of the GNU General -+// Public License (GPL); either version 2, or (at your option) any -+// later version. -+ -+/** -+ * sfunction kernel_string - Retrieves string from kernel memory -+ * @addr: The kernel address to retrieve the string from -+ * -+ * Description: This function returns the null terminated C string -+ * from a given kernel memory address. Reports an error on string -+ * copy fault. -+ */ -+function kernel_string:string (addr:long) { -+ return kernel_string_n(addr, 64 /*TODO: define BPF_MAXSTRINGLEN*/) -+} -+ -+// TODO kernel_string:string(addr:long, err_msg:string) -+// TODO kernel_string2:string(addr:long, err_msg:string) -+ -+/** -+ * sfunction kernel_string - Retrieves string from kernel memory with alternative error string -+ * @addr: The kernel address to retrieve the string from -+ * @err_msg: The error message to return when data isn't available -+ * -+ * Description: This function returns the null terminated C string -+ * from a given kernel memory address. Reports the given error message -+ * on string copy fault. -+ */ -+function kernel_string:string (addr:long, err_msg:string) -+%{ /* bpf */ /* pure */ -+ /* buf = bpf_stk_alloc(BPF_MAXSTRINGLEN); -+ buf[0] = 0x0; // guarantee NUL byte -+ rc = bpf_probe_read_str(buf, n, addr); */ -+ alloc, $buf, BPF_MAXSTRINGLEN; -+ 0x62, $buf, -, -, 0x0; /* stw [$buf+0], 0x0 -- guarantee NUL byte */ -+ call, $rc, bpf_probe_read_str, $buf, BPF_MAXSTRINGLEN, $addr; -+ -+ /* if (rc < 0) return err_msg; -+ return buf; */ -+ 0xa5, rc, 0, _err, -; /* jlt $rc, 0, _err */ -+ 0xbf, $$, $buf, -, -; /* mov $$, $buf */ -+ 0x05, -, -, _done, -; /* ja _done; */ -+ label, _err; -+ 0xbf, $$, $err_msg, -, -; /* mov $$, $err_msg */ -+ label, _done; -+%} -+function kernel_string2:string (addr:long, err_msg:string) { -+ return kernel_string(addr, err_msg); -+} -+ -+// TODO kernel_string_quoted:string(addr:long) -- requires pseudo-loop to quote unprintable chars -+ -+/** -+ * sfunction kernel_string_n - Retrieves string of given length from kernel memory -+ * @addr: The kernel address to retrieve the string from -+ * @n: The maximum length of the string (if not null terminated) -+ * -+ * Description: Returns the C string of a maximum given length from a -+ * given kernel memory address. Reports an error on string copy fault. -+ */ -+function kernel_string_n:string (addr:long, n:long) -+%{ /* bpf */ /* pure */ -+ /* if (n > BPF_MAXSTRINGLEN) n = BPF_MAXSTRINGLEN; */ -+ 0xb5, $n, -, _skip, BPF_MAXSTRINGLEN; /* jle n, BPF_MAXSTRINGLEN, _skip */ -+ 0xb7, $n, -, -, BPF_MAXSTRINGLEN; /* mov $n, BPF_MAXSTRINGLEN */ -+ label, _skip; -+ -+ /* buf = bpf_stk_alloc(BPF_MAXSTRINGLEN); -+ buf[0] = 0x0; // guarantee NUL byte -+ rc = bpf_probe_read_str(buf, n, addr); */ -+ alloc, $buf, BPF_MAXSTRINGLEN; -+ 0x62, $buf, -, -, 0x0; /* stw [buf+0], 0 -- guarantee NUL byte */ -+ call, $rc, probe_read_str, $buf, $n, $addr; /* TODO: should work with bpf_probe_read_str too */ -+ -+ /* TODO pending implementation of error */ -+ /* if (rc < 0) error("...", addr); */ -+ /*0x35, $rc, 0, _done, -; /* jge rc, 0, _done */ -+ /*error, "kernel string copy fault at 0x%p [man error::fault]", $addr; /* TODO document bpf version of error::fault */ -+ /*label, _done;*/ -+ -+ /* return buf; */ -+ 0xbf, $$, $buf, -, -; /* mov $$, buf */ -+%} -+ -+// TODO kernel_string_utf32:string(addr:long) -+// TODO kernel_string_utf32:string(addr:long,err_msg:string) -+// TODO kernel_string2_utf32:string(addr:long,err_msg:string) -+// TODO kernel_string_quoted_utf32:string(addr:long) -+ -+// TODO kernel_string_utf16:string(addr:long) -+// TODO kernel_string_utf16:string(addr:long,err_msg:string) -+// TODO kernel_string2_utf16:string(addr:long,err_msg:string) -+// TODO kernel_string_quoted_utf16:string(addr:long) -+ -+// TODO kernel_long:long(addr:long) -+// TODO kernel_int:long(addr:long) -+// TODO kernel_short:long(addr:long) -+// TODO kernel_char:long(addr:long) -+ -+// TODO kernel_pointer:long(addr:long) -+ -+// TODO kernel_buffer_quoted:string(addr:long,inlen:long) -+// TODO kernel_buffer_quoted:string(addr:long,inlen:long,outlen:long) -+// TODO kernel_buffer_quoted_error:string(addr:long,inlen:long,outlen:long) --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0007-stapbpf-assembler-WIP-6-other-call-functions-s-print.patch b/SOURCES/rhbz1643997.0007-stapbpf-assembler-WIP-6-other-call-functions-s-print.patch deleted file mode 100644 index 1fc397e..0000000 --- a/SOURCES/rhbz1643997.0007-stapbpf-assembler-WIP-6-other-call-functions-s-print.patch +++ /dev/null @@ -1,623 +0,0 @@ -From 1d21523d10628fd14c4a16d5f85d98add9b5c0a6 Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Tue, 23 Oct 2018 13:35:08 -0400 -Subject: [PATCH 07/32] stapbpf assembler WIP #6 :: other call functions - ({s}printf and tapset) - -Only very limited support for tapset functions (restricted to exit() -for now) due to the difficulty of resolving symbols after the semantic -pass is already completed. Could address this in the future. - -* bpf_internal.h (program::use_tmp_space): check for overflow. -(globals::session): new field for systemtap_session (used by function lookup). - -* bpf_translate.cxx (asm_stmt::has_jmp_target): new field. -(operator <<): printing rules for alloc, call. -(bpf_unparser::parse_asm_stmt): remove printf/error, BUGFIX alloc, call, string literal. -Also calculate has_jmp_target in the resulting stmt. -(bpf_unparser::visit_embeddedcode): handle printf, sprintf and exit(). -Also fix the way fallthrough fields are populated to avoid spurious extra jump. -(bpf_unparser::emit_functioncall): new function. Factors out non-staptree code. -(bpf_unparser::visit_functioncall): use new emit_functioncall(). -(print_format_add_tag): new function on std::string. Factors out string operations. -(bpf_unparser::emit_print_format): new function. Factors out non-staptree code. -(bpf_unparser::visit_print_format): use new emit_print_format(). -(translate_bpf_pass): store session in globals. ---- - bpf-internal.h | 5 + - bpf-translate.cxx | 346 +++++++++++++++++++++++++++++++++++++++--------------- - 2 files changed, 255 insertions(+), 96 deletions(-) - -diff --git a/bpf-internal.h b/bpf-internal.h -index 61514db9f..3041bbdf5 100644 ---- a/bpf-internal.h -+++ b/bpf-internal.h -@@ -30,6 +30,7 @@ namespace bpf { - #define MAX_BPF_STACK 512 - #define BPF_REG_SIZE 8 - #define BPF_MAXSTRINGLEN 64 -+// #define BPF_MAXSTRINGLEN 128 // TODO: Longer strings require storage allocator & better printf(). - #define BPF_MAXFORMATLEN 256 - #define BPF_MAXMAPENTRIES 2048 - // TODO: add BPF_MAXSPRINTFLEN -@@ -245,6 +246,7 @@ struct program - { - if (max_tmp_space < bytes) - max_tmp_space = bytes; -+ assert(max_tmp_space <= MAX_BPF_STACK); - } - - void mk_ld(insn_inserter &ins, int sz, value *dest, value *base, int off); -@@ -318,6 +320,9 @@ struct globals - EXIT = 0, - NUM_INTERNALS, // non-ABI - }; -+ -+ // Used to resolve function symbols in embedded code. -+ systemtap_session *session; - }; - } // namespace bpf - -diff --git a/bpf-translate.cxx b/bpf-translate.cxx -index af3f54b50..df22401ad 100644 ---- a/bpf-translate.cxx -+++ b/bpf-translate.cxx -@@ -135,8 +135,10 @@ has_side_effects (expression *e) - return t.side_effects; - } - --/* forward declaration */ -+/* forward declarations */ - struct asm_stmt; -+static void print_format_add_tag(std::string&); -+static void print_format_add_tag(print_format*); - - struct bpf_unparser : public throwing_visitor - { -@@ -238,6 +240,11 @@ struct bpf_unparser : public throwing_visitor - value *emit_bool(expression *e); - value *emit_context_var(bpf_context_vardecl *v); - -+ value *emit_functioncall(functiondecl *f, const std::vector &args); -+ value *emit_print_format(const std::string &format, -+ const std::vector &actual, -+ bool print_to_stream = true); -+ - // Used for the embedded-code assembler: - int64_t parse_imm (const asm_stmt &stmt, const std::string &str); - size_t parse_asm_stmt (embeddedcode *s, size_t start, -@@ -594,24 +601,22 @@ bpf_unparser::visit_block (::block *s) - - ::= label, ; - ::= alloc, , ; -- ::= call, , , , ...; -- ::= printf, , , ...; -- ::= error, , , ...; -+ ::= call, , , , ...; - ::= , , , - , ; - - Supported argument types include: - -- ::= | -- ::= | r | -- $ | $ | $$ | -- ::= | BPF_MAXSTRINGLEN -- ::= | -+ ::= | -+ ::= | - -+ ::= | r | -+ $ | $ | $$ | -+ ::= | BPF_MAXSTRINGLEN | - -+ ::= | - - */ - --// TODO --#define BPF_ASM_DEBUG -+// #define BPF_ASM_DEBUG - - struct asm_stmt { - std::string kind; -@@ -621,6 +626,8 @@ struct asm_stmt { - int64_t off, imm; - - // metadata for jmp instructions -+ // ??? The logic around these flags could be pruned a bit. -+ bool has_jmp_target = false; - bool has_fallthrough = false; - std::string jmp_target, fallthrough; - -@@ -650,6 +657,19 @@ operator << (std::ostream& o, const asm_stmt& stmt) - << stmt.imm << ";" - << (stmt.has_fallthrough ? " +FALLTHROUGH " + stmt.fallthrough : ""); - } -+ else if (stmt.kind == "alloc") -+ { -+ o << "alloc, " << stmt.dest << ", " << stmt.imm << ";"; -+ } -+ else if (stmt.kind == "call") -+ { -+ o << "call, " << stmt.dest << ", "; -+ for (unsigned k = 0; k < stmt.params.size(); k++) -+ { -+ o << stmt.params[k]; -+ o << (k >= stmt.params.size() - 1 ? ";" : ", "); -+ } -+ } - else - o << ""; - return o; -@@ -711,7 +731,7 @@ bpf_unparser::parse_asm_stmt (embeddedcode *s, size_t start, - { - char c = code[pos]; - char c2 = pos + 1 < n ? code [pos + 1] : 0; -- if (isspace(c)) -+ if (isspace(c) && !in_string) - continue; // skip - else if (in_comment) - { -@@ -799,6 +819,10 @@ bpf_unparser::parse_asm_stmt (embeddedcode *s, size_t start, - adjusted_loc.column++; - } - -+ // Now populate the statement data. -+ -+ stmt = asm_stmt(); // clear pre-existing data -+ - // set token with adjusted source location - stmt.tok = s->tok->adjust_location(adjusted_loc); - adjusted_toks.push_back(stmt.tok); -@@ -830,14 +854,7 @@ bpf_unparser::parse_asm_stmt (embeddedcode *s, size_t start, - throw SEMANTIC_ERROR (_F("invalid bpf embeddedcode syntax (call expects at least 2 args, found %lu)", args.size()-1), stmt.tok); - stmt.kind = args[0]; - stmt.dest = args[1]; -- for (unsigned k = 2; k < args.size(); k++) -- stmt.params.push_back(args[k]); -- } -- else if (args[0] == "printf" || args[0] == "error") -- { -- if (args.size() < 2) -- throw SEMANTIC_ERROR (_F("invalid bpf embeddedcode syntax (%s expects at least 2 args, found %lu)", args[0].c_str(), args.size()-1), stmt.tok); -- stmt.kind = args[0]; -+ assert(stmt.params.empty()); - for (unsigned k = 2; k < args.size(); k++) - stmt.params.push_back(args[k]); - } -@@ -855,16 +872,16 @@ bpf_unparser::parse_asm_stmt (embeddedcode *s, size_t start, - stmt.dest = args[1]; - stmt.src1 = args[2]; - -- bool has_jmp_target = -+ stmt.has_jmp_target = - BPF_CLASS(stmt.code) == BPF_JMP - && BPF_OP(stmt.code) != BPF_EXIT - && BPF_OP(stmt.code) != BPF_CALL; - stmt.has_fallthrough = // only for jcond -- has_jmp_target -+ stmt.has_jmp_target - && BPF_OP(stmt.code) != BPF_JA; - // XXX: stmt.fallthrough is computed by visit_embeddedcode - -- if (has_jmp_target) -+ if (stmt.has_jmp_target) - { - stmt.off = 0; - stmt.jmp_target = args[3]; -@@ -1168,6 +1185,7 @@ bpf_unparser::visit_embeddedcode (embeddedcode *s) - - if (after_jump != NULL && stmt.kind == "label") - { -+ after_jump->has_fallthrough = true; - after_jump->fallthrough = stmt.dest; - } - else if (after_jump != NULL) -@@ -1183,6 +1201,7 @@ bpf_unparser::visit_embeddedcode (embeddedcode *s) - label_map[fallthrough_label] = b; - set_block(b); - -+ after_jump->has_fallthrough = true; - after_jump->fallthrough = fallthrough_label; - } - -@@ -1205,6 +1224,12 @@ bpf_unparser::visit_embeddedcode (embeddedcode *s) - after_label = false; - after_jump = &*it; // be sure to refer to original, not copied stmt - } -+ else if (stmt.kind == "opcode" && BPF_CLASS(stmt.code) == BPF_JMP -+ && BPF_OP(stmt.code) != BPF_CALL /* CALL stays in the same block */) -+ { -+ after_label = false; -+ after_jump = &*it; // be sure to refer to original, not copied stmt -+ } - else - { - after_label = false; -@@ -1216,7 +1241,7 @@ bpf_unparser::visit_embeddedcode (embeddedcode *s) - "fallthrough on final asm_stmt"), stmt.tok); - - // emit statements -- bool jumped_already = true; -+ bool jumped_already = false; - set_block(entry_block); - for (std::vector::iterator it = statements.begin(); - it != statements.end(); it++) -@@ -1234,24 +1259,27 @@ bpf_unparser::visit_embeddedcode (embeddedcode *s) - else if (stmt.kind == "alloc") - { - /* Reserve stack space and store its address in dest. */ -- int ofs = this_prog.max_tmp_space + stmt.imm; -- value *dest = get_asm_reg(stmt, stmt.dest); -+ int ofs = -this_prog.max_tmp_space - stmt.imm; - this_prog.use_tmp_space(-ofs); -+ // ??? Consider using a storage allocator and this_prog.new_obj(). -+ -+ value *dest = get_asm_reg(stmt, stmt.dest); - this_prog.mk_binary(this_ins, BPF_ADD, dest, - this_prog.lookup_reg(BPF_REG_10) /*frame*/, - this_prog.new_imm(ofs)); - } - else if (stmt.kind == "call") - { -+ assert (!stmt.params.empty()); - std::string func_name = stmt.params[0]; - bpf_func_id hid = bpf_function_id(func_name); - if (hid != __BPF_FUNC_MAX_ID) - { -- // TODO diagnostic: check if the number of arguments is correct -+ // ??? For diagnostics: check if the number of arguments is correct. - regno r = BPF_REG_1; unsigned nargs = 0; - for (unsigned k = 1; k < stmt.params.size(); k++) - { -- // ??? Could make params optional to avoid this part, -+ // ??? Could make params optional to avoid the MOVs, - // ??? since the calling convention is well-known. - value *from_reg = emit_asm_arg(stmt, stmt.params[k]); - value *to_reg = this_prog.lookup_reg(r); -@@ -1259,30 +1287,117 @@ bpf_unparser::visit_embeddedcode (embeddedcode *s) - nargs++; r++; - } - this_prog.mk_call(this_ins, hid, nargs); -- this_prog.mk_mov(this_ins, get_asm_reg(stmt, stmt.dest), -- this_prog.lookup_reg(BPF_REG_0) /* returnval */); -- // ??? Could make stmt.dest optional to avoid this extra mov, -- // ??? since the BPF_REG_0 convention is well-known. -+ if (stmt.dest != "-") -+ { -+ value *dest = get_asm_reg(stmt, stmt.dest); -+ this_prog.mk_mov(this_ins, dest, -+ this_prog.lookup_reg(BPF_REG_0) /* returnval */); -+ } -+ // ??? For diagnostics: check other cases with stmt.dest. -+ } -+ else if (func_name == "printf" || func_name == "sprintf") -+ { -+ if (stmt.params.size() < 2) -+ throw SEMANTIC_ERROR (_F("bpf embeddedcode '%s' expects format string, " -+ "none provided", func_name.c_str()), -+ stmt.tok); -+ std::string format = stmt.params[1]; -+ if (format.size() < 2 || format[0] != '"' -+ || format[format.size()-1] != '"') -+ throw SEMANTIC_ERROR (_F("bpf embeddedcode '%s' expects format string, " -+ "but first parameter is not a string literal", -+ func_name.c_str()), stmt.tok); -+ format = format.substr(1,format.size()-2); /* strip quotes */ -+ format = translate_escapes(format); -+ -+ bool print_to_stream = (func_name == "printf"); -+ if (print_to_stream) -+ print_format_add_tag(format); -+ -+ size_t format_bytes = format.size() + 1; -+ if (format_bytes > BPF_MAXFORMATLEN) -+ throw SEMANTIC_ERROR(_("Format string for print too long"), stmt.tok); -+ -+ std::vector args; -+ for (unsigned k = 2; k < stmt.params.size(); k++) -+ args.push_back(emit_asm_arg(stmt, stmt.params[k])); -+ if (args.size() > 3) -+ throw SEMANTIC_ERROR(_NF("additional argument to print", -+ "too many arguments to print (%zu)", -+ args.size(), args.size()), stmt.tok); -+ -+ value *retval = emit_print_format(format, args, print_to_stream); -+ if (retval != NULL && stmt.dest != "-") -+ { -+ 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. - } - else - { -- // TODO function_name = params[0]; -- // TODO args = parse_reg(params[1]), parse_reg(params[2]), ... -- // TODO emit_functioncall() with good bits from visit_functioncall() -- throw SEMANTIC_ERROR (_("BUG: bpf embeddedcode non-helper 'call' not yet supported"), -- stmt.tok); -+ // TODO: Experimental code for supporting basic functioncalls. -+ // Needs improvement and simplification to work with full generality. -+ // But thus far, it is sufficient for calling exit(). -+#if 1 -+ if (func_name != "exit") -+ throw SEMANTIC_ERROR(_("BUG: bpf embeddedcode non-helper 'call' operation only supports printf(),sprintf(),exit() for now"), stmt.tok); -+#elif 1 -+ throw SEMANTIC_ERROR(_("BUG: bpf embeddedcode non-helper 'call' operation only supports printf(),sprintf() for now"), stmt.tok); -+#endif -+#if 1 -+ // ???: Passing systemtap_session through all the way to here -+ // seems intrusive, but less intrusive than moving -+ // embedded-code assembly to the translate_globals() pass. -+ symresolution_info sym (*glob.session); -+ functioncall *call = new functioncall; -+ call->tok = stmt.tok; -+ unsigned nargs = stmt.params.size() - 1; -+ std::vector fds -+ = sym.find_functions (call, func_name, nargs, stmt.tok); -+ delete call; -+ -+ if (fds.empty()) -+ // ??? Could call levenshtein_suggest() as in -+ // symresolution_info::visit_functioncall(). -+ throw SEMANTIC_ERROR(_("bpf embeddedcode unresolved function call"), stmt.tok); -+ if (fds.size() > 1) -+ throw SEMANTIC_ERROR(_("bpf embeddedcode unhandled function overloading"), stmt.tok); -+ functiondecl *f = fds[0]; -+ // TODO: Imitation of semantic_pass_symbols, does not -+ // cover full generality of the lookup process. -+ update_visitor_loop (*glob.session, glob.session->code_filters, f->body); -+ sym.current_function = f; sym.current_probe = 0; -+ f->body->visit (&sym); -+ -+ // ??? For now, always inline the function call. -+ for (auto i = func_calls.begin(); i != func_calls.end(); ++i) -+ if (f == *i) -+ throw SEMANTIC_ERROR (_("unhandled function recursion"), stmt.tok); -+ -+ // Collect the function arguments. -+ std::vector args; -+ for (unsigned k = 1; k < stmt.params.size(); k++) -+ args.push_back(emit_asm_arg(stmt, stmt.params[k])); -+ -+ if (args.size () != f->formal_args.size()) -+ throw SEMANTIC_ERROR(_F("bpf embeddedcode call to function '%s' " -+ "expected %zu arguments, got %zu", -+ func_name.c_str(), -+ f->formal_args.size(), args.size()), -+ stmt.tok); -+ -+ value *retval = emit_functioncall(f, args); -+ if (stmt.dest != "-") -+ { -+ 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. -+#endif - } - } -- else if (stmt.kind == "printf" || stmt.kind == "error") -- { -- // TODO Note that error() should be modeled on the tapset function in tapset/logging.stp -- // TODO format = params[0]; -- // TODO args = parse_reg(params[1]), parse_reg(params[2]), ... -- // TODO emit_print_format() with good bits from visit_print_format() -- // TODO if (stmt.kind == "error") emit functioncall to exit() -- throw SEMANTIC_ERROR (_("BUG: bpf embeddedcode 'printf/error' not yet supported"), -- stmt.tok); -- } - else if (stmt.kind == "opcode") - { - emit_asm_opcode (stmt, label_map); -@@ -1291,9 +1406,13 @@ bpf_unparser::visit_embeddedcode (embeddedcode *s) - throw SEMANTIC_ERROR (_F("BUG: bpf embeddedcode contains unexpected " - "asm_stmt kind '%s'", stmt.kind.c_str()), - stmt.tok); -- jumped_already = stmt.has_fallthrough; - if (stmt.has_fallthrough) -- set_block(label_map[stmt.fallthrough]); -+ { -+ jumped_already = true; -+ set_block(label_map[stmt.fallthrough]); -+ } -+ else -+ jumped_already = false; - } - - // housekeeping -- deallocate adjusted_toks along with statements -@@ -1779,7 +1898,8 @@ bpf_unparser::visit_logical_and_expr (logical_and_expr* e) - result = emit_bool (e); - } - --// TODO: This matches translate.cxx, but it looks like the functionality is disabled in the parser. -+// ??? This matches the code in translate.cxx, but it looks like the -+// functionality has been disabled in the SystemTap parser. - void - bpf_unparser::visit_compound_expression (compound_expression* e) - { -@@ -2573,30 +2693,17 @@ bpf_unparser::emit_str_arg(value *arg, int ofs, value *str) - emit_mov(arg, out); - } - --void --bpf_unparser::visit_functioncall (functioncall *e) -+value * -+bpf_unparser::emit_functioncall (functiondecl *f, const std::vector& args) - { -- // ??? For now, always inline the function call. -- // ??? Function overloading isn't handled. -- if (e->referents.size () != 1) -- throw SEMANTIC_ERROR (_("unhandled function overloading"), e->tok); -- functiondecl *f = e->referents[0]; -- -- for (auto i = func_calls.begin(); i != func_calls.end(); ++i) -- if (f == *i) -- throw SEMANTIC_ERROR (_("unhandled function recursion"), e->tok); -- -- assert (e->args.size () == f->formal_args.size ()); -- - // Create a new map for the function's local variables. - locals_map *locals = new_locals(f->locals); - -- // Evaluate the function arguments and install in the map. -- for (unsigned n = e->args.size (), i = 0; i < n; ++i) -+ // Install locals in the map. -+ unsigned n = args.size(); -+ for (unsigned i = 0; i < n; ++i) - { -- value *r = this_prog.new_reg (); -- emit_mov (r, emit_expr (e->args[i])); -- const locals_map::value_type v (f->formal_args[i], r); -+ const locals_map::value_type v (f->formal_args[i], args[i]); - auto ok = locals->insert (v); - assert (ok.second); - } -@@ -2622,7 +2729,47 @@ bpf_unparser::visit_functioncall (functioncall *e) - this_locals = old_locals; - delete locals; - -- result = retval; -+ return retval; -+} -+ -+void -+bpf_unparser::visit_functioncall (functioncall *e) -+{ -+ // ??? Function overloading isn't handled. -+ if (e->referents.size () != 1) -+ throw SEMANTIC_ERROR (_("unhandled function overloading"), e->tok); -+ functiondecl *f = e->referents[0]; -+ -+ // ??? For now, always inline the function call. -+ for (auto i = func_calls.begin(); i != func_calls.end(); ++i) -+ if (f == *i) -+ throw SEMANTIC_ERROR (_("unhandled function recursion"), e->tok); -+ -+ // XXX: Should have been checked in earlier pass. -+ assert (e->args.size () == f->formal_args.size ()); -+ -+ // Evaluate and collect the function arguments. -+ std::vector args; -+ for (unsigned n = e->args.size (), i = 0; i < n; ++i) -+ { -+ value *r = this_prog.new_reg (); -+ emit_mov (r, emit_expr (e->args[i])); -+ args.push_back(r); -+ } -+ -+ result = emit_functioncall(f, args); -+} -+ -+static void -+print_format_add_tag(std::string& format) -+{ -+ // surround the string with ... to facilitate -+ // stapbpf recovering it from debugfs. -+ std::string start_tag = module_name; -+ start_tag = "<" + start_tag.erase(4,1) + ">"; -+ std::string end_tag = start_tag + "\n"; -+ end_tag.insert(1, "/"); -+ format = start_tag + format + end_tag; - } - - static void -@@ -2677,6 +2824,32 @@ print_format_add_tag(print_format *e) - } - } - -+value * -+bpf_unparser::emit_print_format (const std::string& format, -+ const std::vector& actual, -+ bool print_to_stream) -+{ -+ size_t nargs = actual.size(); -+ -+ // The bpf verifier requires that the format string be stored on the -+ // bpf program stack. This is handled by bpf-opt.cxx lowering STR values. -+ size_t format_bytes = format.size() + 1; -+ this_prog.mk_mov(this_ins, this_prog.lookup_reg(BPF_REG_1), -+ this_prog.new_str(format)); -+ emit_mov(this_prog.lookup_reg(BPF_REG_2), this_prog.new_imm(format_bytes)); -+ for (size_t i = 0; i < nargs; ++i) -+ emit_mov(this_prog.lookup_reg(BPF_REG_3 + i), actual[i]); -+ -+ if (print_to_stream) -+ this_prog.mk_call(this_ins, BPF_FUNC_trace_printk, nargs + 2); -+ else -+ { -+ this_prog.mk_call(this_ins, BPF_FUNC_sprintf, nargs + 2); -+ return this_prog.lookup_reg(BPF_REG_0); -+ } -+ return NULL; -+} -+ - void - bpf_unparser::visit_print_format (print_format *e) - { -@@ -2696,9 +2869,9 @@ bpf_unparser::visit_print_format (print_format *e) - "too many arguments to print (%zu)", - e->args.size(), e->args.size()), e->tok); - -- value *actual[3] = { NULL, NULL, NULL }; -+ std::vector actual; - for (i = 0; i < nargs; ++i) -- actual[i] = emit_expr(e->args[i]); -+ actual.push_back(emit_expr(e->args[i])); - - std::string format; - if (e->print_with_format) -@@ -2750,36 +2923,17 @@ bpf_unparser::visit_print_format (print_format *e) - if (e->print_with_newline) - format += '\n'; - -- // surround the string with ... to facilitate -- // stapbpf recovering it from debugfs. - if (e->print_to_stream) -- { -- std::string start_tag = module_name; -- start_tag = "<" + start_tag.erase(4,1) + ">"; -- std::string end_tag = start_tag + "\n"; -- end_tag.insert(1, "/"); -- format = start_tag + format + end_tag; -- } -+ print_format_add_tag(format); - } - -- // The bpf verifier requires that the format string be stored on the -- // bpf program stack. This is handled by bpf-opt.cxx lowering STR values. - size_t format_bytes = format.size() + 1; - if (format_bytes > BPF_MAXFORMATLEN) - throw SEMANTIC_ERROR(_("Format string for print too long"), e->tok); -- this_prog.mk_mov(this_ins, this_prog.lookup_reg(BPF_REG_1), -- this_prog.new_str(format)); -- emit_mov(this_prog.lookup_reg(BPF_REG_2), this_prog.new_imm(format_bytes)); -- for (i = 0; i < nargs; ++i) -- emit_mov(this_prog.lookup_reg(BPF_REG_3 + i), actual[i]); - -- if (e->print_to_stream) -- this_prog.mk_call(this_ins, BPF_FUNC_trace_printk, nargs + 2); -- else -- { -- this_prog.mk_call(this_ins, BPF_FUNC_sprintf, nargs + 2); -- result = this_prog.lookup_reg(BPF_REG_0); -- } -+ value *retval = emit_print_format(format, actual, e->print_to_stream); -+ if (retval != NULL) -+ result = retval; - } - - // } // anon namespace -@@ -3409,7 +3563,7 @@ translate_bpf_pass (systemtap_session& s) - return 1; - - BPF_Output eo(fd); -- globals glob; -+ globals glob; glob.session = &s; - int ret = 0; - const token* t = 0; - try --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0008-stapbpf-assembler-WIP-7-fixed-kernel_string-tapset-a.patch b/SOURCES/rhbz1643997.0008-stapbpf-assembler-WIP-7-fixed-kernel_string-tapset-a.patch deleted file mode 100644 index b8c3069..0000000 --- a/SOURCES/rhbz1643997.0008-stapbpf-assembler-WIP-7-fixed-kernel_string-tapset-a.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 06835f4435a706d2495245116417a48178435c4c Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Wed, 24 Oct 2018 12:46:55 -0400 -Subject: [PATCH 08/32] stapbpf assembler WIP #7 :: fixed kernel_string() - tapset and testcase - -* tapset/bpf/conversions.stp (kernel_string_n): enable error path. -* tapset/logging.stp (abort): note future work. -* testsuite/systemtap.bpf/bpf_tests/context_vars3.stp: new testcase. ---- - tapset/bpf/conversions.stp | 14 ++++++++------ - tapset/logging.stp | 4 ++-- - testsuite/systemtap.bpf/bpf_tests/context_vars3.stp | 15 +++++++++++++++ - 3 files changed, 25 insertions(+), 8 deletions(-) - create mode 100644 testsuite/systemtap.bpf/bpf_tests/context_vars3.stp - -diff --git a/tapset/bpf/conversions.stp b/tapset/bpf/conversions.stp -index d741ec584..1140a6875 100644 ---- a/tapset/bpf/conversions.stp -+++ b/tapset/bpf/conversions.stp -@@ -44,8 +44,10 @@ function kernel_string:string (addr:long, err_msg:string) - 0xa5, rc, 0, _err, -; /* jlt $rc, 0, _err */ - 0xbf, $$, $buf, -, -; /* mov $$, $buf */ - 0x05, -, -, _done, -; /* ja _done; */ -+ - label, _err; - 0xbf, $$, $err_msg, -, -; /* mov $$, $err_msg */ -+ - label, _done; - %} - function kernel_string2:string (addr:long, err_msg:string) { -@@ -67,21 +69,21 @@ function kernel_string_n:string (addr:long, n:long) - /* if (n > BPF_MAXSTRINGLEN) n = BPF_MAXSTRINGLEN; */ - 0xb5, $n, -, _skip, BPF_MAXSTRINGLEN; /* jle n, BPF_MAXSTRINGLEN, _skip */ - 0xb7, $n, -, -, BPF_MAXSTRINGLEN; /* mov $n, BPF_MAXSTRINGLEN */ -- label, _skip; - -+ label, _skip; - /* buf = bpf_stk_alloc(BPF_MAXSTRINGLEN); - buf[0] = 0x0; // guarantee NUL byte - rc = bpf_probe_read_str(buf, n, addr); */ - alloc, $buf, BPF_MAXSTRINGLEN; - 0x62, $buf, -, -, 0x0; /* stw [buf+0], 0 -- guarantee NUL byte */ -- call, $rc, probe_read_str, $buf, $n, $addr; /* TODO: should work with bpf_probe_read_str too */ -+ call, $rc, probe_read_str, $buf, $n, $addr; /* TODO: should work if the helper is named bpf_probe_read_str() too */ - -- /* TODO pending implementation of error */ - /* if (rc < 0) error("...", addr); */ -- /*0x35, $rc, 0, _done, -; /* jge rc, 0, _done */ -- /*error, "kernel string copy fault at 0x%p [man error::fault]", $addr; /* TODO document bpf version of error::fault */ -- /*label, _done;*/ -+ 0x35, $rc, 0, _done, -; /* jge rc, 0, _done */ -+ call, -, printf, "ERROR: kernel string copy fault at 0x%p [man error::fault]", $addr; /* TODO document stapbpf version of error::fault */ -+ call, -, exit; - -+ label, _done; - /* return buf; */ - 0xbf, $$, $buf, -, -; /* mov $$, buf */ - %} -diff --git a/tapset/logging.stp b/tapset/logging.stp -index 839239b8f..441ad2c21 100644 ---- a/tapset/logging.stp -+++ b/tapset/logging.stp -@@ -95,8 +95,8 @@ function abort () - %: - { /* unprivileged */ /* bpf */ - _set_exit_status() -- printf("ERROR: abort() not supported yet\n") -- exit() /* TODO: need to abort the execution flow immediately */ -+ printf("ERROR: abort() not supported in eBPF backend\n") -+ exit() /* TODO: need to abort the execution flow immediately -- could be handled with a special assembly operation */ - } - %) - %) -diff --git a/testsuite/systemtap.bpf/bpf_tests/context_vars3.stp b/testsuite/systemtap.bpf/bpf_tests/context_vars3.stp -new file mode 100644 -index 000000000..97cd338d6 ---- /dev/null -+++ b/testsuite/systemtap.bpf/bpf_tests/context_vars3.stp -@@ -0,0 +1,15 @@ -+probe begin { -+ printf("BEGIN\n") -+} -+ -+probe kernel.function("vfs_read") { -+ if ($file != 0 && $file->f_cred->usage->counter > 0 && $buf != 0) { -+ filename = kernel_string($file->f_path->dentry->d_name->name) -+ printf("found %s\n", filename) -+ exit() -+ } -+} -+ -+probe end { -+ printf("END PASS\n") -+} --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0009-stapbpf-assembler-WIP-8-bpf-asm.exp-driver-and-more-.patch b/SOURCES/rhbz1643997.0009-stapbpf-assembler-WIP-8-bpf-asm.exp-driver-and-more-.patch deleted file mode 100644 index 2b0e48b..0000000 --- a/SOURCES/rhbz1643997.0009-stapbpf-assembler-WIP-8-bpf-asm.exp-driver-and-more-.patch +++ /dev/null @@ -1,356 +0,0 @@ -From 17e0a28b75e8a5961fcfae52b631eebf9e9fd118 Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Wed, 24 Oct 2018 13:30:29 -0400 -Subject: [PATCH 09/32] stapbpf assembler WIP #8 :: bpf-asm.exp driver and more - testcases - ---- - testsuite/systemtap.bpf/asm_tests/branch.stp | 14 ++- - .../systemtap.bpf/asm_tests/err-printf_args.stp | 9 ++ - testsuite/systemtap.bpf/asm_tests/err_numeric.stp | 1 - - testsuite/systemtap.bpf/asm_tests/leniency.stp | 14 ++- - testsuite/systemtap.bpf/asm_tests/printf-basic.stp | 9 ++ - testsuite/systemtap.bpf/asm_tests/printf.stp | 16 ++++ - testsuite/systemtap.bpf/asm_tests/simple.stp | 9 +- - testsuite/systemtap.bpf/asm_tests/string.stp | 21 +++-- - testsuite/systemtap.bpf/asm_tests/temporary.stp | 9 +- - testsuite/systemtap.bpf/asm_tests/unreachable.stp | 17 ++++ - testsuite/systemtap.bpf/bpf-asm.exp | 105 +++++++++++++++++++++ - 11 files changed, 205 insertions(+), 19 deletions(-) - create mode 100644 testsuite/systemtap.bpf/asm_tests/err-printf_args.stp - create mode 100644 testsuite/systemtap.bpf/asm_tests/printf-basic.stp - create mode 100644 testsuite/systemtap.bpf/asm_tests/printf.stp - create mode 100644 testsuite/systemtap.bpf/asm_tests/unreachable.stp - create mode 100644 testsuite/systemtap.bpf/bpf-asm.exp - -diff --git a/testsuite/systemtap.bpf/asm_tests/branch.stp b/testsuite/systemtap.bpf/asm_tests/branch.stp -index aa22bf195..0e49213df 100644 ---- a/testsuite/systemtap.bpf/asm_tests/branch.stp -+++ b/testsuite/systemtap.bpf/asm_tests/branch.stp -@@ -6,7 +6,6 @@ function foo:long (x:long) %{ /* bpf */ /* pure */ - label, _bar; - 0xb7, $$, -, -, 50; /* mov $$, 50 */ - label, _done; -- /* 0xbf, $$, $$, -, -; /* dummy op */ - %} - - function bar:long (x:long) { -@@ -14,9 +13,14 @@ function bar:long (x:long) { - } - - probe begin { -- printf("foo(1)=%d should be %d\n", foo(1), bar(1)) -- printf("foo(8)=%d should be %d\n", foo(8), bar(8)) -- printf("foo(15)=%d should be %d\n", foo(15), bar(15)) -- exit() -+ printf("U foo(1)=%d should be %d\n", foo(1), bar(1)) -+ printf("U foo(8)=%d should be %d\n", foo(8), bar(8)) -+ printf("U foo(15)=%d should be %d\n", foo(15), bar(15)) - } - -+probe kernel.function("vfs_read") { -+ printf("K foo(1)=%d should be %d\n", foo(1), bar(1)) -+ printf("K foo(8)=%d should be %d\n", foo(8), bar(8)) -+ printf("K foo(15)=%d should be %d\n", foo(15), bar(15)) -+ exit() -+} -diff --git a/testsuite/systemtap.bpf/asm_tests/err-printf_args.stp b/testsuite/systemtap.bpf/asm_tests/err-printf_args.stp -new file mode 100644 -index 000000000..eb4adc00f ---- /dev/null -+++ b/testsuite/systemtap.bpf/asm_tests/err-printf_args.stp -@@ -0,0 +1,9 @@ -+function foo:long (x:long) %{ /* bpf */ -+ call, -, printf, "x = 0x%p causing exit\n", $x, $x, $x, $x; -+ 0xb7, $$, -, -, 0x0; /* mov $$, 0 */ -+%} -+ -+probe begin { -+ printf("U x = 10 should print:\n"); foo(10) -+ exit() -+} -diff --git a/testsuite/systemtap.bpf/asm_tests/err_numeric.stp b/testsuite/systemtap.bpf/asm_tests/err_numeric.stp -index 9428e5704..ed82b32a1 100644 ---- a/testsuite/systemtap.bpf/asm_tests/err_numeric.stp -+++ b/testsuite/systemtap.bpf/asm_tests/err_numeric.stp -@@ -15,4 +15,3 @@ probe begin { - printf("foo(15)=%d should be %d\n", foo(15), bar(15)) - exit() - } -- -diff --git a/testsuite/systemtap.bpf/asm_tests/leniency.stp b/testsuite/systemtap.bpf/asm_tests/leniency.stp -index 939061158..1db1ec7fd 100644 ---- a/testsuite/systemtap.bpf/asm_tests/leniency.stp -+++ b/testsuite/systemtap.bpf/asm_tests/leniency.stp -@@ -9,9 +9,17 @@ function foo:long (x:long) %{ /* bpf */ /* pure */ - label, _done; - %} - -+function bar:long (x:long) { -+ if (x < 10) return 17 else return 16 -+} -+ - probe begin { -- printf("foo(1)=%d\n", foo(1)) -- printf("foo(15)=%d\n", foo(15)) -- exit() -+ printf("U foo(1)=%d should be %d\n", foo(1), bar(1)) -+ printf("U foo(15)=%d should be %d\n", foo(15), bar(15)) - } - -+probe kernel.function("vfs_read") { -+ printf("K foo(1)=%d should be %d\n", foo(1), bar(1)) -+ printf("K foo(15)=%d should be %d\n", foo(15), bar(15)) -+ exit() -+} -diff --git a/testsuite/systemtap.bpf/asm_tests/printf-basic.stp b/testsuite/systemtap.bpf/asm_tests/printf-basic.stp -new file mode 100644 -index 000000000..ffa8e01eb ---- /dev/null -+++ b/testsuite/systemtap.bpf/asm_tests/printf-basic.stp -@@ -0,0 +1,9 @@ -+function foo:long (x:long) %{ /* bpf */ -+ call, -, printf, "x = %p \n", $x; -+ 0xb7, $$, -, -, 0x0; /* mov $$, 0 */ -+%} -+ -+probe begin { -+ printf("U 'x = 0xa' should print:\n"); foo(10) -+ exit() -+} -diff --git a/testsuite/systemtap.bpf/asm_tests/printf.stp b/testsuite/systemtap.bpf/asm_tests/printf.stp -new file mode 100644 -index 000000000..4bfa34648 ---- /dev/null -+++ b/testsuite/systemtap.bpf/asm_tests/printf.stp -@@ -0,0 +1,16 @@ -+function foo:long (x:long) %{ /* bpf */ /* calls:exit */ -+ 0xb5, $x, -, _skip, 20; /* jle n, 20, _skip */ -+ call, -, printf, "x = %d causing exit\n", $x; /* like error() */ -+ call, -, exit; -+ label, _skip; -+ call, -, printf, "x = %d not causing exit\n", $x; -+ 0xb7, $$, -, -, 0x0; /* mov $$, 0 */ -+%} -+ -+probe begin { -+ printf("U 'x = 10' should print:\n"); foo(10) -+} -+ -+probe kernel.function("vfs_read") { -+ printf("K 'x = 25' should print:\n"); foo(25) -+} -diff --git a/testsuite/systemtap.bpf/asm_tests/simple.stp b/testsuite/systemtap.bpf/asm_tests/simple.stp -index 17184a139..f8dd693c5 100644 ---- a/testsuite/systemtap.bpf/asm_tests/simple.stp -+++ b/testsuite/systemtap.bpf/asm_tests/simple.stp -@@ -5,7 +5,12 @@ function foo:long (x:long) %{ /* bpf */ /* pure */ - %} - - probe begin { -- printf("foo(1)=%d, should be 99\n", foo(1)) -- printf("foo(15)=%d, should be 85\n", foo(15)) -+ printf("U foo(1)=%d, should be 99\n", foo(1)) -+ printf("U foo(15)=%d, should be 85\n", foo(15)) -+} -+ -+probe kernel.function("vfs_read") { -+ printf("K foo(1)=%d, should be 99\n", foo(1)) -+ printf("K foo(15)=%d, should be 85\n", foo(15)) - exit() - } -diff --git a/testsuite/systemtap.bpf/asm_tests/string.stp b/testsuite/systemtap.bpf/asm_tests/string.stp -index dce665c14..6ecbe08da 100644 ---- a/testsuite/systemtap.bpf/asm_tests/string.stp -+++ b/testsuite/systemtap.bpf/asm_tests/string.stp -@@ -1,4 +1,4 @@ --function foo:long (x:long) %{ /* bpf */ /* pure */ -+function foo:string (x:long) %{ /* bpf */ /* pure */ - /* if x <= 10 then "fifty" else "one-hundred" */ - 0xd5, $x, -, _bar, 10; /* jsle $x, 10, _bar */ - 0xbf, $$, "one-hundred", -, -; /* mov $$, "one-hundred" */ -@@ -9,14 +9,23 @@ function foo:long (x:long) %{ /* bpf */ /* pure */ - /* 0xbf, $$, $$, -, -; /* dummy op */ - %} - --function bar:long (x:long) { -- if (x <= 10) return 50 else return 100 -+function bar:string (x:long) { -+ if (x <= 10) return "fifty" else return "one-hundred" - } - - probe begin { -- printf("foo(1)=%d should be %d\n", foo(1), bar(1)) -- printf("foo(8)=%d should be %d\n", foo(8), bar(8)) -- printf("foo(15)=%d should be %d\n", foo(15), bar(15)) -+ printf("U foo(1)=%s should be %s\n", foo(1), bar(1)) -+ printf("U foo(8)=%s should be %s\n", foo(8), bar(8)) -+ printf("U foo(15)=%s should be %s\n", foo(15), bar(15)) -+} -+ -+probe kernel.function("vfs_read") { -+ printf("K foo(1)=%s should be %s\n", bar(1), bar(1)) -+ printf("K foo(8)=%s should be %s\n", bar(8), bar(8)) -+ printf("K foo(15)=%s should be %s\n", bar(15), bar(15)) -+ # printf("K foo(1)=%s should be %s\n", foo(1), bar(1)) -+ # printf("K foo(8)=%s should be %s\n", foo(8), bar(8)) -+ # printf("K foo(15)=%s should be %s\n", foo(15), bar(15)) - exit() - } - -diff --git a/testsuite/systemtap.bpf/asm_tests/temporary.stp b/testsuite/systemtap.bpf/asm_tests/temporary.stp -index 153c759ba..7cec89bb3 100644 ---- a/testsuite/systemtap.bpf/asm_tests/temporary.stp -+++ b/testsuite/systemtap.bpf/asm_tests/temporary.stp -@@ -8,7 +8,12 @@ function foo:long (x:long) %{ /* bpf */ /* pure */ - %} - - probe begin { -- printf("foo(1)=%d, should be 99*3=297\n", foo(1)) -- printf("foo(15)=%d, should be 85*18=1530\n", foo(15)) -+ printf("U foo(1)=%d, should be 99*3=297\n", foo(1)) -+ printf("U foo(15)=%d, should be 85*18=1530\n", foo(15)) -+} -+ -+probe kernel.function("vfs_read") { -+ printf("K foo(1)=%d, should be 99*3=297\n", foo(1)) -+ printf("K foo(15)=%d, should be 85*18=1530\n", foo(15)) - exit() - } -diff --git a/testsuite/systemtap.bpf/asm_tests/unreachable.stp b/testsuite/systemtap.bpf/asm_tests/unreachable.stp -new file mode 100644 -index 000000000..b629fd5cb ---- /dev/null -+++ b/testsuite/systemtap.bpf/asm_tests/unreachable.stp -@@ -0,0 +1,17 @@ -+/* testcase for an early bug that would generate duplicate jump */ -+function foo:long (x:long) %{ /* bpf */ -+ /* the code in the middle is unreachable */ -+ 0xd5, $x, -, _bar, 20; /* jsle $x, 20, _done */ -+ 0xb7, $$, -, -, 100; /* mov $$, 100 */ -+ 0x05, -, -, _done, -; -+ label, _bar; -+ 0xb7, $$, -, -, 50; /* mov $$, 50 */ -+ label, _done; -+%} -+ -+probe kernel.function("vfs_read") { -+ x = 10 -+ if (x > 12) printf("unreachable\n") -+ printf ("got %d (should be 50)\n", foo(x)) -+ exit() -+} -diff --git a/testsuite/systemtap.bpf/bpf-asm.exp b/testsuite/systemtap.bpf/bpf-asm.exp -new file mode 100644 -index 000000000..a53c7bcc4 ---- /dev/null -+++ b/testsuite/systemtap.bpf/bpf-asm.exp -@@ -0,0 +1,105 @@ -+# bpf-asm.exp -+# -+# TODO: Very basic test driver. Need to work out a way of signaling correctness. -+ -+set testdir "$srcdir/$subdir/asm_tests" -+ -+proc stapbpf_run { TEST_NAME args } { -+ global rc -+ set rc -1 -+ -+ # return codes -+ set pass 0 -+ #set fail 1 -+ #set bad_output 2 -+ set eof_start 3 -+ set eof_end 4 -+ set timeout_start 5 -+ set timeout_end 6 -+ set invalid_prog 7 -+ set comp_err 8 -+ -+ set cmd [concat stap -vg --runtime=bpf $args] -+ send_log "executing: $cmd\n" -+ eval spawn $cmd -+ set mypid [exp_pid -i $spawn_id] -+ expect { -+ -timeout 30 -+ -re {Pass 5: starting run} { -+ expect { -+ -timeout 20 -+ -re {Pass 5: run completed} { -+ set rc $pass -+ } -+ -re "bpf program load failed:" { set rc $invalid_prog } -+ default { -+ set rc $bad_output -+ } -+ timeout { -+ set rc $timeout_end -+ kill -INT -$mypid -+ } -+ eof { -+ set rc $eof_end -+ } -+ } -+ } -+ -re "semantic error:" { set rc $comp_err } -+ -re "bpf program load failed:" { set rc $invalid_prog } -+ timeout { -+ set rc $timeout_start -+ kill -INT -$mypid -+ } -+ eof { -+ set rc $eof_start -+ } -+ } -+ # again for good measure with KILL after 3s -+ kill -INT -$mypid 3 -+ catch close -+ wait -+ return $rc -+} -+ -+set stap_files [lsort [glob -nocomplain $testdir/*.stp]] -+ -+foreach file $stap_files { -+ global mypid -+ set mypid 0 -+ set test [file tail $file] -+ if {! [installtest_p]} { untested $test; continue } -+ if {! [bpf_p]} { untested $test; continue } -+ -+ set errtest_p [regexp {^err} [file tail $file]] -+ verbose -log "Running $file" -+ switch [stapbpf_run $test $file] { -+ 0 { -+ if $errtest_p { -+ fail "$test unexpected success" -+ } else { -+ pass $test -+ } -+ } -+ 1 { fail "$test incorrect result" } -+ 2 { fail "$test unexpected output" } -+ 3 { fail "$test eof (startup)" } -+ 4 { fail "$test eof (shutdown)" } -+ 5 { fail "$test timeout (startup)" } -+ 6 { fail "$test timeout (startup)" } -+ 7 { fail "$test invalid bpf program" } -+ 8 { -+ if $errtest_p { -+ pass $test -+ } else { -+ fail "$test compilation" -+ } -+ } -+ default { fail "$test unknown return value" } -+ } -+ -+ if { $mypid > 0 } { -+ kill -INT -$mypid 3 -+ catch close -+ wait -+ } -+} --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0010-bpf-translate.cxx-plug-an-exception-gap-in-is_numeri.patch b/SOURCES/rhbz1643997.0010-bpf-translate.cxx-plug-an-exception-gap-in-is_numeri.patch deleted file mode 100644 index bb9127c..0000000 --- a/SOURCES/rhbz1643997.0010-bpf-translate.cxx-plug-an-exception-gap-in-is_numeri.patch +++ /dev/null @@ -1,35 +0,0 @@ -From baabce812704826c5f7b20ed4afcca816cab7967 Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Thu, 25 Oct 2018 12:19:53 -0400 -Subject: [PATCH 10/32] bpf-translate.cxx :: plug an exception gap in - is_numeric() - ---- - bpf-translate.cxx | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/bpf-translate.cxx b/bpf-translate.cxx -index df22401ad..bf55c56b4 100644 ---- a/bpf-translate.cxx -+++ b/bpf-translate.cxx -@@ -681,11 +681,15 @@ is_numeric (const std::string &str) - size_t pos = 0; - try { - stol(str, &pos, 0); -- } catch (std::invalid_argument &e) { -+ } catch (const std::invalid_argument &e) { - return false; -- } catch (std::out_of_range &e) { -+ } catch (const std::out_of_range &e) { - /* XXX: probably numeric but not valid; give up */ - return false; -+ } catch (...) { -+ /* XXX: handle other errors the same way */ -+ std::cerr << "BUG: bpf assembler -- is_numeric() saw unexpected exception" << std::endl; -+ return false; - } - return (pos == str.size()); - } --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0011-session.cxx-enable-caching-for-bpf-backend.patch b/SOURCES/rhbz1643997.0011-session.cxx-enable-caching-for-bpf-backend.patch deleted file mode 100644 index 874d110..0000000 --- a/SOURCES/rhbz1643997.0011-session.cxx-enable-caching-for-bpf-backend.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 1f892756af4de555fb1dc70bd1c7437eecde0d31 Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Fri, 26 Oct 2018 11:15:13 -0400 -Subject: [PATCH 11/32] session.cxx :: enable caching for bpf backend - ---- - session.cxx | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/session.cxx b/session.cxx -index eed28bf7e..ffad3b2b5 100644 ---- a/session.cxx -+++ b/session.cxx -@@ -1701,7 +1701,7 @@ systemtap_session::parse_cmdline_runtime (const string& opt_runtime) - return false; - #else - runtime_mode = bpf_runtime; -- use_cache = use_script_cache = false; -+ // use_cache = use_script_cache = false; // XXX: From early BPF development. Delete after making sure the cache doesn't break anything. - #endif - } - else if (opt_runtime == string("dyninst")) --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0012-Adjust-the-BPF-translate-error-report-formatting-to-.patch b/SOURCES/rhbz1643997.0012-Adjust-the-BPF-translate-error-report-formatting-to-.patch deleted file mode 100644 index f094685..0000000 --- a/SOURCES/rhbz1643997.0012-Adjust-the-BPF-translate-error-report-formatting-to-.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 311eea74540d2ebbf61f4c795a180aec79dc2b00 Mon Sep 17 00:00:00 2001 -From: William Cohen -Date: Tue, 30 Oct 2018 14:20:46 -0400 -Subject: [PATCH 12/32] Adjust the BPF translate error report formatting to - work on 32-bit architectures - -The 32-bit architectures such as arm and i686 had arguments in the -error reporting that did not match up with the %lu or %ld formatting. -Used type casting and %llu and %lld to avoid variation between 32-bit -and 64-bit architectures. ---- - bpf-translate.cxx | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/bpf-translate.cxx b/bpf-translate.cxx -index bf55c56b4..bb133bae5 100644 ---- a/bpf-translate.cxx -+++ b/bpf-translate.cxx -@@ -840,14 +840,14 @@ bpf_unparser::parse_asm_stmt (embeddedcode *s, size_t start, - if (args[0] == "label") - { - if (args.size() != 2) -- throw SEMANTIC_ERROR (_F("invalid bpf embeddedcode syntax (label expects 1 arg, found %lu)", args.size()-1), stmt.tok); -+ throw SEMANTIC_ERROR (_F("invalid bpf embeddedcode syntax (label expects 1 arg, found %llu)", (long long) args.size()-1), stmt.tok); - stmt.kind = args[0]; - stmt.dest = args[1]; - } - else if (args[0] == "alloc") - { - if (args.size() != 3) -- throw SEMANTIC_ERROR (_F("invalid bpf embeddedcode syntax (alloc expects 2 args, found %lu)", args.size()-1), stmt.tok); -+ throw SEMANTIC_ERROR (_F("invalid bpf embeddedcode syntax (alloc expects 2 args, found %llu)", (long long) args.size()-1), stmt.tok); - stmt.kind = args[0]; - stmt.dest = args[1]; - stmt.imm = parse_imm(stmt, args[2]); -@@ -855,7 +855,7 @@ bpf_unparser::parse_asm_stmt (embeddedcode *s, size_t start, - else if (args[0] == "call") - { - if (args.size() < 3) -- throw SEMANTIC_ERROR (_F("invalid bpf embeddedcode syntax (call expects at least 2 args, found %lu)", args.size()-1), stmt.tok); -+ throw SEMANTIC_ERROR (_F("invalid bpf embeddedcode syntax (call expects at least 2 args, found %llu)", (long long) args.size()-1), stmt.tok); - stmt.kind = args[0]; - stmt.dest = args[1]; - assert(stmt.params.empty()); -@@ -865,7 +865,7 @@ bpf_unparser::parse_asm_stmt (embeddedcode *s, size_t start, - else if (is_numeric(args[0])) - { - if (args.size() != 5) -- throw SEMANTIC_ERROR (_F("invalid bpf embeddedcode syntax (opcode expects 4 args, found %lu)", args.size()-1), stmt.tok); -+ throw SEMANTIC_ERROR (_F("invalid bpf embeddedcode syntax (opcode expects 4 args, found %llu)", (long long) args.size()-1), stmt.tok); - stmt.kind = "opcode"; - try { - stmt.code = stoul(args[0], 0, 0); -@@ -1128,7 +1128,7 @@ bpf_unparser::emit_asm_opcode (const asm_stmt &stmt, - } - - if (stmt.off != (int16_t)stmt.off) -- throw SEMANTIC_ERROR (_F("offset field '%ld' out of range in bpf code", stmt.off), stmt.tok); -+ throw SEMANTIC_ERROR (_F("offset field '%lld' out of range in bpf code", (long long) stmt.off), stmt.tok); - - if (op_jmp) - { --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0013-bpf-translate.cxx-fix-segfault-with-malformed-regist.patch b/SOURCES/rhbz1643997.0013-bpf-translate.cxx-fix-segfault-with-malformed-regist.patch deleted file mode 100644 index b7bc8fd..0000000 --- a/SOURCES/rhbz1643997.0013-bpf-translate.cxx-fix-segfault-with-malformed-regist.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 99ee8b19901f4908e2a2942731c34e03aadd9549 Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Tue, 30 Oct 2018 17:10:53 -0400 -Subject: [PATCH 13/32] bpf-translate.cxx :: fix segfault with malformed - register - ---- - bpf-translate.cxx | 9 +++++++-- - testsuite/systemtap.bpf/asm_tests/err-regparse.stp | 9 +++++++++ - 2 files changed, 16 insertions(+), 2 deletions(-) - create mode 100644 testsuite/systemtap.bpf/asm_tests/err-regparse.stp - -diff --git a/bpf-translate.cxx b/bpf-translate.cxx -index bb133bae5..d46dae44a 100644 ---- a/bpf-translate.cxx -+++ b/bpf-translate.cxx -@@ -952,8 +952,13 @@ bpf_unparser::emit_asm_arg (const asm_stmt &stmt, const std::string &arg, - { - /* arg is a register number */ - std::string reg = arg[0] == 'r' ? arg.substr(1) : arg; -- unsigned long num = stoul(reg, 0, 0); -- if (num > 10) -+ unsigned long num; -+ bool parsed = false; -+ try { -+ num = stoul(reg, 0, 0); -+ parsed = true; -+ } catch (std::exception &e) {} // XXX: invalid_argument, out_of_range -+ if (!parsed || num > 10) - throw SEMANTIC_ERROR (_F("invalid bpf register '%s'", - arg.c_str()), stmt.tok); - return this_prog.lookup_reg(num); -diff --git a/testsuite/systemtap.bpf/asm_tests/err-regparse.stp b/testsuite/systemtap.bpf/asm_tests/err-regparse.stp -new file mode 100644 -index 000000000..ba66800e6 ---- /dev/null -+++ b/testsuite/systemtap.bpf/asm_tests/err-regparse.stp -@@ -0,0 +1,9 @@ -+function foo:long () %{ /* bpf */ /* pure */ -+ 0xb7, $rc, -, -, 50; /* mov $rc, 50 */ -+ 0xbf, $$, rc, -, -; /* mov $$, $rc -- TYPO */ -+%} -+ -+probe begin { -+ printf("foo()=%d should be fifty\n", foo()) -+ exit() -+} --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0014-bpf-asm.exp-bugfix-bad_output-does-occur.patch b/SOURCES/rhbz1643997.0014-bpf-asm.exp-bugfix-bad_output-does-occur.patch deleted file mode 100644 index eff101c..0000000 --- a/SOURCES/rhbz1643997.0014-bpf-asm.exp-bugfix-bad_output-does-occur.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0e59ff192856462702191f1e6d87e5fdbfd158a3 Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Tue, 30 Oct 2018 17:11:45 -0400 -Subject: [PATCH 14/32] bpf-asm.exp bugfix :: bad_output does occur - ---- - testsuite/systemtap.bpf/bpf-asm.exp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/testsuite/systemtap.bpf/bpf-asm.exp b/testsuite/systemtap.bpf/bpf-asm.exp -index a53c7bcc4..8925cb049 100644 ---- a/testsuite/systemtap.bpf/bpf-asm.exp -+++ b/testsuite/systemtap.bpf/bpf-asm.exp -@@ -11,7 +11,7 @@ proc stapbpf_run { TEST_NAME args } { - # return codes - set pass 0 - #set fail 1 -- #set bad_output 2 -+ set bad_output 2 - set eof_start 3 - set eof_end 4 - set timeout_start 5 --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0015-tapset-bpf-conversions.stp-bugfix-helper-name-in-ker.patch b/SOURCES/rhbz1643997.0015-tapset-bpf-conversions.stp-bugfix-helper-name-in-ker.patch deleted file mode 100644 index 80ecc02..0000000 --- a/SOURCES/rhbz1643997.0015-tapset-bpf-conversions.stp-bugfix-helper-name-in-ker.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 4e9775b55b5ddd7447c100894ab816a849c2c8cc Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Tue, 30 Oct 2018 17:13:28 -0400 -Subject: [PATCH 15/32] tapset/bpf/conversions.stp bugfix :: helper name in - kernel_string(addr, err_msg) - ---- - tapset/bpf/conversions.stp | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/tapset/bpf/conversions.stp b/tapset/bpf/conversions.stp -index 1140a6875..88d63b70a 100644 ---- a/tapset/bpf/conversions.stp -+++ b/tapset/bpf/conversions.stp -@@ -34,10 +34,10 @@ function kernel_string:string (addr:long, err_msg:string) - %{ /* bpf */ /* pure */ - /* buf = bpf_stk_alloc(BPF_MAXSTRINGLEN); - buf[0] = 0x0; // guarantee NUL byte -- rc = bpf_probe_read_str(buf, n, addr); */ -+ rc = bpf_probe_read_str(buf, BPF_MAXSTRINGLEN, addr); */ - alloc, $buf, BPF_MAXSTRINGLEN; - 0x62, $buf, -, -, 0x0; /* stw [$buf+0], 0x0 -- guarantee NUL byte */ -- call, $rc, bpf_probe_read_str, $buf, BPF_MAXSTRINGLEN, $addr; -+ call, $rc, probe_read_str, $buf, BPF_MAXSTRINGLEN, $addr; - - /* if (rc < 0) return err_msg; - return buf; */ --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0016-tapset-bpf-context.stp-add-execname-triage-other-fun.patch b/SOURCES/rhbz1643997.0016-tapset-bpf-context.stp-add-execname-triage-other-fun.patch deleted file mode 100644 index 23cd7d7..0000000 --- a/SOURCES/rhbz1643997.0016-tapset-bpf-context.stp-add-execname-triage-other-fun.patch +++ /dev/null @@ -1,175 +0,0 @@ -From deb88d0b1fef10177ab197b066f434c720253f8d Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Tue, 30 Oct 2018 17:29:46 -0400 -Subject: [PATCH 16/32] tapset/bpf/context.stp :: add execname(), triage other - functions - -* tapset/bpf/context.stp: Notes on other functions that could be added. -(execname): New tapset function. - -* tapset/linux/context.stp: Move pexecname() to a more logical location. ---- - tapset/bpf/context.stp | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ - tapset/linux/context.stp | 30 +++++++++++----------- - 2 files changed, 81 insertions(+), 15 deletions(-) - -diff --git a/tapset/bpf/context.stp b/tapset/bpf/context.stp -index 45dcd4d71..55e0f871b 100644 ---- a/tapset/bpf/context.stp -+++ b/tapset/bpf/context.stp -@@ -6,6 +6,34 @@ - // Public License (GPL); either version 2, or (at your option) any - // later version. - -+/** -+ * sfunction execname - Returns the execname of a target process (or group of processes) -+ * -+ * Description: Returns the execname of a target process (or group of processes). -+ */ -+function execname:string () -+%{ /* bpf */ /* pure */ /* unprivileged */ /* stable */ -+ /* buf = bpf_stk_alloc(BPF_MAXSTRINGLEN); -+ buf[0] = 0x0; // guarantee NUL byte -+ rc = get_current_comm(buf, BPF_MAXSTRINGLEN); */ -+ alloc, $buf, BPF_MAXSTRINGLEN; -+ 0x62, $buf, -, -, 0x0; /* stw [$buf+0], 0x0 -- guarantee NUL byte */ -+ call, $rc, get_current_comm, $buf, BPF_MAXSTRINGLEN; -+ -+ /* if (rc < 0) return err_msg; -+ return buf; */ -+ 0xa5, $rc, 0, _err, -; /* jlt $rc, 0, _err */ -+ 0xbf, $$, $buf, -, -; /* mov $$, $buf */ -+ 0x05, -, -, _done, -; /* ja _done */ -+ -+ label, _err; -+ 0xbf, $$, "", -, -; /* mov $$, */ -+ -+ label, _done; -+%} -+ -+// TODO: pexecname () -+ - /** - * sfunction pid - Returns the ID of a thread group - * -@@ -20,6 +48,8 @@ function pid:long () - 0x77, $$, 0, 0, 32 /* rshk $$, 32 */ - %} - -+// TODO: ns_pid:long () -+ - /** - * sfunction tid - Returns the thread ID of a target process - * -@@ -33,6 +63,14 @@ function tid:long () - 0xbc, $$, 0, 0, 0 /* movwx $$, r0 */ - %} - -+// TODO: ns_tid:long () -+// TODO: ppid:long () -+// TODO: ns_ppid:long () -+// TODO: pgrp:long () -+// TODO: ns_pgrp:long () -+// TODO: sid:long () -+// TODO: ns_sid:long () -+ - /** - * sfunction gid - Returns the group ID of a target process - * -@@ -46,6 +84,10 @@ function gid:long () - 0x77, $$, 0, 0, 32 /* rshk $$, 32 */ - %} - -+// TODO: ns_gid:long () -+// TODO: egid:long () -+// TODO: ns_egid:long () -+ - /** - * sfunction uid - Returns the user ID of a target process - * -@@ -58,6 +100,12 @@ function uid:long () - 0xbc, $$, 0, 0, 0 /* movwx $$, r0 */ - %} - -+// TODO: ns_uid:long () -+// TODO: euid:long () -+// TODO: ns_euid:long () -+// XXX: is_myproc () is only relevant for unprivileged use of eBPF (still theoretical). -+ -+// TODO: Old systemtap-compat scripts should not be running on eBPF backend in the first place? - /** - * sfunction cpuid - Returns the current cpu number - * -@@ -82,3 +130,21 @@ function cpu:long () - 0x85, 0, 0, 0, 8; /* call BPF_FUNC_get_smp_processor_id */ - 0xbf, $$, 0, 0, 0 /* movx $$, r0 */ - %} -+ -+// TODO: registers_valid:long () -+// TODO: user_mode:long () -+// TODO: is_return:long () -+// TODO: target:long () -+// TODO: module_name:string () -+// XXX: module_size:string () -- not clear if this should refer to the entire .bo or to just the current eBPF routine. -+// TODO: stp_pid:long () -+// XXX: remote_id:long (), remote_uri:string() -- pending an evaluation of remote eBPF execution. -+// XXX: stack_size() -- not clear if this should be the eBPF stack size or the kernel stack size. -+// XXX: stack_used(),stack_unused() probably a fairly ill-defined idea with the eBPF stack. -+// TODO: Other context functions for info about things like eBPF maps. -+ -+// TODO: addr:long () -+// TODO: uaddr:long () -+// XXX: cmdline_args:string(n:long, m:long, delim:string) -- requires string concatenation & loops. -+// TODO: cmdline_arg:string(n:long) -+// XXX: cmdline_string:string() -- requires string concatenation & loops. -diff --git a/tapset/linux/context.stp b/tapset/linux/context.stp -index 2bd405186..46b1f6b32 100644 ---- a/tapset/linux/context.stp -+++ b/tapset/linux/context.stp -@@ -19,6 +19,21 @@ function execname:string () - strlcpy (STAP_RETVALUE, current->comm, MAXSTRINGLEN); - %} - -+/** -+ * sfunction pexecname - Returns the execname of a target process's parent process -+ * -+ * Description: This function returns the execname of a target -+ * process's parent procces. -+ */ -+function pexecname:string () -+%{ /* pure */ /* unprivileged */ /* stable */ -+#if defined(STAPCONF_REAL_PARENT) -+ strlcpy (STAP_RETVALUE, current->real_parent->comm, MAXSTRINGLEN); -+#else -+ strlcpy (STAP_RETVALUE, current->parent->comm, MAXSTRINGLEN); -+#endif -+%} -+ - /** - * sfunction pid - Returns the ID of a target process - * -@@ -153,21 +168,6 @@ function ns_sid:long () - else STAP_RETURN (rc); - %} - --/** -- * sfunction pexecname - Returns the execname of a target process's parent process -- * -- * Description: This function returns the execname of a target -- * process's parent procces. -- */ --function pexecname:string () --%{ /* pure */ /* unprivileged */ /* stable */ --#if defined(STAPCONF_REAL_PARENT) -- strlcpy (STAP_RETVALUE, current->real_parent->comm, MAXSTRINGLEN); --#else -- strlcpy (STAP_RETVALUE, current->parent->comm, MAXSTRINGLEN); --#endif --%} -- - /** - * sfunction gid - Returns the group ID of a target process - * --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0017-PR23849-temporarily-disable-stapbpf-script-caching.patch b/SOURCES/rhbz1643997.0017-PR23849-temporarily-disable-stapbpf-script-caching.patch deleted file mode 100644 index 394eab7..0000000 --- a/SOURCES/rhbz1643997.0017-PR23849-temporarily-disable-stapbpf-script-caching.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 49f6a9a448b5df9af354897bc6ee2eb68496b3c2 Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Thu, 1 Nov 2018 16:13:07 -0400 -Subject: [PATCH 17/32] PR23849 -- temporarily disable stapbpf script caching - ---- - session.cxx | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/session.cxx b/session.cxx -index ffad3b2b5..f70a7ccfd 100644 ---- a/session.cxx -+++ b/session.cxx -@@ -1701,7 +1701,13 @@ systemtap_session::parse_cmdline_runtime (const string& opt_runtime) - return false; - #else - runtime_mode = bpf_runtime; -- // use_cache = use_script_cache = false; // XXX: From early BPF development. Delete after making sure the cache doesn't break anything. -+ -+ // TODO: From early BPF development. Remove after making sure the -+ // cache doesn't break anything. Currently removal is blocked -+ // by PR22330 (module name encoded in trace_printk() calls, -+ // using up a lot of stack space for the cacheable script -+ // names). -+ use_cache = use_script_cache = false; - #endif - } - else if (opt_runtime == string("dyninst")) --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0018-tapset-bpf-task.stp-rudiment-of-task-tapset.patch b/SOURCES/rhbz1643997.0018-tapset-bpf-task.stp-rudiment-of-task-tapset.patch deleted file mode 100644 index 980d42b..0000000 --- a/SOURCES/rhbz1643997.0018-tapset-bpf-task.stp-rudiment-of-task-tapset.patch +++ /dev/null @@ -1,62 +0,0 @@ -From ba62b58974fd25f7281fa151411c8e32b3951fbb Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Fri, 2 Nov 2018 12:22:01 -0400 -Subject: [PATCH 18/32] tapset/bpf/task.stp :: rudiment of task tapset - ---- - tapset/bpf/task.stp | 20 ++++++++++++++++++++ - testsuite/systemtap.bpf/bpf_tests/task1.stp | 15 +++++++++++++++ - 2 files changed, 35 insertions(+) - create mode 100644 tapset/bpf/task.stp - create mode 100644 testsuite/systemtap.bpf/bpf_tests/task1.stp - -diff --git a/tapset/bpf/task.stp b/tapset/bpf/task.stp -new file mode 100644 -index 000000000..9f558a166 ---- /dev/null -+++ b/tapset/bpf/task.stp -@@ -0,0 +1,20 @@ -+// task information tapset -+// Copyright (C) 2018 Red Hat Inc. -+// -+// This file is part of systemtap, and is free software. You can -+// redistribute it and/or modify it under the terms of the GNU General -+// Public License (GPL); either version 2, or (at your option) any -+// later version. -+ -+@__private30 function _task_cur:long() -+%{ /* bpf */ /* pure */ -+ call, $$, get_current_task; -+%} -+ -+/** -+ * sfunction task_current - The current task_struct of the current task -+ */ -+function task_current:long () { -+ // TODO: return & @task(_task_cur()) -+ return & @cast(_task_cur(), "task_struct") -+} -diff --git a/testsuite/systemtap.bpf/bpf_tests/task1.stp b/testsuite/systemtap.bpf/bpf_tests/task1.stp -new file mode 100644 -index 000000000..b0faab361 ---- /dev/null -+++ b/testsuite/systemtap.bpf/bpf_tests/task1.stp -@@ -0,0 +1,15 @@ -+probe begin { -+ printf("BEGIN\n") -+} -+ -+probe kernel.function("vfs_read") { -+ // TODO: PR23816, task.stp tapset -+ printf("vfs_read by %s", execname()) -+ printf("/%s", kernel_string(@cast(task_current(), "task_struct")->comm)) -+ printf(" PID %d/%d\n", pid(), @cast(task_current(), "task_struct")->tgid) -+ exit() -+} -+ -+probe end { -+ printf("END PASS\n") -+} --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0019-PR23829-fallback-defines-__BPF_FUNC_MAPPER-and-BPF_J.patch b/SOURCES/rhbz1643997.0019-PR23829-fallback-defines-__BPF_FUNC_MAPPER-and-BPF_J.patch deleted file mode 100644 index f4b8241..0000000 --- a/SOURCES/rhbz1643997.0019-PR23829-fallback-defines-__BPF_FUNC_MAPPER-and-BPF_J.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 0d45550a184cc5a9f10187a97b9ef8dc7fa13f31 Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Fri, 2 Nov 2018 16:49:23 -0400 -Subject: [PATCH 19/32] PR23829 :: fallback defines __BPF_FUNC_MAPPER and - BPF_J{LT,LE,SLT,SLE} for older kernels - ---- - bpf-base.cxx | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - bpf-internal.h | 11 +++++++++++ - 2 files changed, 70 insertions(+) - -diff --git a/bpf-base.cxx b/bpf-base.cxx -index 277927b72..210efa9aa 100644 ---- a/bpf-base.cxx -+++ b/bpf-base.cxx -@@ -140,6 +140,65 @@ is_commutative(opcode code) - std::map bpf_func_name_map; - std::map bpf_func_id_map; - -+/* PR23829: On older kernels, bpf.h does not define __BPF_FUNC_MAPPER. -+ As a fallback, use the *earliest* __BPF_FUNC_MAPPER, so stapbpf -+ will not try helpers that only exist on subsequent kernels. -+ -+ TODO: This isn't perfect since even older kernels don't have -+ some of these helpers. -+ -+ XXX: Note the build limitation in that SystemTap must be compiled -+ against a recent kernel to be able to use the helpers from that -+ kernel. That's also the case when building against recent bpf.h -+ with __BPF_FUNC_MAPPER, so this workaround is not the source of the -+ problem. */ -+#ifndef __BPF_FUNC_MAPPER -+#define __BPF_FUNC_MAPPER(FN) \ -+ FN(unspec), \ -+ FN(map_lookup_elem), \ -+ FN(map_update_elem), \ -+ FN(map_delete_elem), \ -+ FN(probe_read), \ -+ FN(ktime_get_ns), \ -+ FN(trace_printk), \ -+ FN(get_prandom_u32), \ -+ FN(get_smp_processor_id), \ -+ FN(skb_store_bytes), \ -+ FN(l3_csum_replace), \ -+ FN(l4_csum_replace), \ -+ FN(tail_call), \ -+ FN(clone_redirect), \ -+ FN(get_current_pid_tgid), \ -+ FN(get_current_uid_gid), \ -+ FN(get_current_comm), \ -+ FN(get_cgroup_classid), \ -+ FN(skb_vlan_push), \ -+ FN(skb_vlan_pop), \ -+ FN(skb_get_tunnel_key), \ -+ FN(skb_set_tunnel_key), \ -+ FN(perf_event_read), \ -+ FN(redirect), \ -+ FN(get_route_realm), \ -+ FN(perf_event_output), \ -+ FN(skb_load_bytes), \ -+ FN(get_stackid), \ -+ FN(csum_diff), \ -+ FN(skb_get_tunnel_opt), \ -+ FN(skb_set_tunnel_opt), \ -+ FN(skb_change_proto), \ -+ FN(skb_change_type), \ -+ FN(skb_under_cgroup), \ -+ FN(get_hash_recalc), \ -+ FN(get_current_task), \ -+ FN(probe_write_user), \ -+ FN(current_task_under_cgroup), \ -+ FN(skb_change_tail), \ -+ FN(skb_pull_data), \ -+ FN(csum_update), \ -+ FN(set_hash_invalid), \ -+ -+#endif -+ - void - init_bpf_helper_tables () // TODO call before script translation - { -diff --git a/bpf-internal.h b/bpf-internal.h -index 3041bbdf5..82cba2c79 100644 ---- a/bpf-internal.h -+++ b/bpf-internal.h -@@ -21,6 +21,17 @@ extern "C" { - #include - } - -+/* PR23829: These eBPF opcodes were added in recent kernels, and the -+ following 'ad hoc' defines are only used by the embedded-code -+ assembler. The code generator will convert these opcodes to -+ equivalent operations valid for earlier eBPF. */ -+#ifndef BPF_JLT -+#define BPF_JLT 0xa0 /* LT is unsigned, '<' */ -+#define BPF_JLE 0xb0 /* LE is unsigned, '<=' */ -+#define BPF_JSLT 0xc0 /* SLT is signed, '<' */ -+#define BPF_JSLE 0xd0 /* SLE is signed, '<=' */ -+#endif -+ - struct systemtap_session; - struct derived_probe; - struct vardecl; --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0020-PR23860-partial-fix-fix-BPF_NEG-opcode-generation.patch b/SOURCES/rhbz1643997.0020-PR23860-partial-fix-fix-BPF_NEG-opcode-generation.patch deleted file mode 100644 index 4d096e9..0000000 --- a/SOURCES/rhbz1643997.0020-PR23860-partial-fix-fix-BPF_NEG-opcode-generation.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 7b8a9050aa8666e29d19f2eea9917afa72fe00ae Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Mon, 5 Nov 2018 16:58:21 -0500 -Subject: [PATCH 20/32] PR23860 partial fix: fix BPF_NEG opcode generation. - -Plus some improved diagnostics on malformed code. - -* bpf-base.cxx (value::print): Don't abort() on unknown operand. -(opcode_name): Don't abort() on unknown opcode. -(insn::print): Don't abort() on malformed insn. -(program::mk_binary): Ensure BPF_NEG src==dest, don't use BPF_X. ---- - bpf-base.cxx | 15 ++++++++++----- - 1 file changed, 10 insertions(+), 5 deletions(-) - -diff --git a/bpf-base.cxx b/bpf-base.cxx -index 210efa9aa..24b610cf3 100644 ---- a/bpf-base.cxx -+++ b/bpf-base.cxx -@@ -32,7 +32,7 @@ value::print(std::ostream &o) const - case TMPREG: - return o << "t" << reg_val; - default: -- abort(); -+ return o << ""; - } - } - -@@ -359,7 +359,7 @@ opcode_name(opcode op) - case BPF_JMP | BPF_JSET | BPF_K: opn = "jsetk"; break; - - default: -- abort(); -+ opn = ""; - } - - return opn; -@@ -457,7 +457,7 @@ insn::print(std::ostream &o) const - return o << opn << "\t" << *src0 << "," << *src1; - - default: -- abort (); -+ return o << ""; - } - } - -@@ -705,10 +705,15 @@ program::mk_binary(insn_inserter &ins, opcode op, value *dest, - void - program::mk_unary(insn_inserter &ins, opcode op, value *dest, value *src) - { -+ assert (op == BPF_NEG); // XXX: BPF_NEG is the only unary operator so far. -+ -+ if (dest != src) // src is not used for BPF_NEG. BPF negates in-place. -+ mk_mov(ins, dest, src); -+ - insn *i = ins.new_insn(); -- i->code = BPF_ALU64 | BPF_X | op; -+ i->code = BPF_ALU64 | op; // BPF_X is not used for BPF_NEG. - i->dest = dest; -- i->src0 = src; -+ i->src0 = dest; // XXX: dest as an ersatz 'source'. - } - - void --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0021-bpf-behind-the-scenes-useful-DEBUG_CODEGEN-diagnosti.patch b/SOURCES/rhbz1643997.0021-bpf-behind-the-scenes-useful-DEBUG_CODEGEN-diagnosti.patch deleted file mode 100644 index 71d8dca..0000000 --- a/SOURCES/rhbz1643997.0021-bpf-behind-the-scenes-useful-DEBUG_CODEGEN-diagnosti.patch +++ /dev/null @@ -1,320 +0,0 @@ -From 31ce3fd0cd21e1a808c417f813b3b5285aeb938a Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Tue, 6 Nov 2018 12:32:38 -0500 -Subject: [PATCH 21/32] bpf behind-the-scenes :: useful DEBUG_CODEGEN - diagnostic - ---- - bpf-base.cxx | 10 ++++++++++ - bpf-internal.h | 21 +++++++++++++++++++++ - bpf-opt.cxx | 28 +++++++++++++++++----------- - bpf-translate.cxx | 26 ++++++++++++++++++++++++-- - 4 files changed, 72 insertions(+), 13 deletions(-) - -diff --git a/bpf-base.cxx b/bpf-base.cxx -index 24b610cf3..5d132bcd1 100644 ---- a/bpf-base.cxx -+++ b/bpf-base.cxx -@@ -368,6 +368,10 @@ opcode_name(opcode op) - std::ostream & - insn::print(std::ostream &o) const - { -+#ifdef DEBUG_CODEGEN -+ if (note != "") -+ o << "{" << note << "} "; -+#endif - const char *opn = opcode_name (code); - - switch (code) -@@ -541,6 +545,12 @@ insn * - insn_inserter::new_insn() - { - insn *n = new insn; -+#ifdef DEBUG_CODEGEN -+ if (!notes.empty()) -+ n->note = notes.top(); -+ else -+ n->note = ""; -+#endif - insert(n); - return n; - } -diff --git a/bpf-internal.h b/bpf-internal.h -index 82cba2c79..75fefb769 100644 ---- a/bpf-internal.h -+++ b/bpf-internal.h -@@ -48,6 +48,8 @@ namespace bpf { - // 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(). - -+// #define DEBUG_CODEGEN -+ - typedef unsigned short regno; - static const regno max_regno = BPF_MAXINSNS; - static const regno noreg = -1; -@@ -135,6 +137,9 @@ struct insn - value *src0; // The destination input, pre-allocation - value *src1; // The usual source register operand - insn *prev, *next; // Linked list of insns in the block -+#ifdef DEBUG_CODEGEN -+ std::string note; // For additional diagnostics. -+#endif - - insn(); - -@@ -198,8 +203,18 @@ private: - public: - block *b; - insn *i; -+#ifdef DEBUG_CODEGEN -+ std::stack notes; -+#endif - - insn_inserter(block *bb, insn *ii) : b(bb), i(ii) { } -+ insn_inserter(block *bb, insn *ii, const std::string& note) : b(bb), i(ii) { -+#ifdef DEBUG_CODEGEN -+ notes.push(note); -+#else -+ (void)note; // unused -+#endif -+ } - virtual ~insn_inserter() { } - virtual void insert(insn *i) = 0; - -@@ -214,6 +229,8 @@ struct insn_before_inserter : public insn_inserter - { - insn_before_inserter() : insn_inserter(NULL, NULL) { } - insn_before_inserter(block *b, insn *i) : insn_inserter(b,i) { } -+ insn_before_inserter(block *b, insn *i, const std::string& note) -+ : insn_inserter(b,i,note) { } - virtual void insert(insn *i); - }; - -@@ -221,6 +238,8 @@ struct insn_after_inserter : public insn_inserter - { - insn_after_inserter() : insn_inserter(NULL, NULL) { } - insn_after_inserter(block *b, insn *i) : insn_inserter(b,i) { } -+ insn_after_inserter(block *b, insn *i, const std::string& note) -+ : insn_inserter(b,i,note) { } - virtual void insert(insn *i); - }; - -@@ -228,6 +247,8 @@ struct insn_append_inserter : public insn_after_inserter - { - insn_append_inserter() : insn_after_inserter(NULL, NULL) { } - insn_append_inserter(block *b) : insn_after_inserter(b, NULL) { } -+ insn_append_inserter(block *b, const std::string& note) -+ : insn_after_inserter(b, NULL, note) { } - }; - - struct program -diff --git a/bpf-opt.cxx b/bpf-opt.cxx -index c2e30a690..904b33b46 100644 ---- a/bpf-opt.cxx -+++ b/bpf-opt.cxx -@@ -59,7 +59,7 @@ lower_str_values(program &p) - value *s0 = j->src0; - if (s0 && s0->is_str()) - { -- insn_before_inserter ins(b, j); -+ insn_before_inserter ins(b, j, "str"); - std::string str0 = s0->str(); - value *new_s0 = alloc_literal_str(p, ins, str0); - j->src0 = new_s0; -@@ -68,7 +68,7 @@ lower_str_values(program &p) - value *s1 = j->src1; - if (s1 && s1->is_str()) - { -- insn_before_inserter ins(b, j); -+ insn_before_inserter ins(b, j, "str"); - std::string str1 = s1->str(); - value *new_s1 = alloc_literal_str(p, ins, str1); - j->src1 = new_s1; -@@ -97,7 +97,7 @@ fixup_operands(program &p) - if (s1 && s1->is_imm() && s1->imm() != (int32_t)s1->imm()) - { - value *n = p.new_reg(); -- insn_before_inserter ins(b, j); -+ insn_before_inserter ins(b, j, "opt"); - p.mk_mov(ins, n, s1); - j->src1 = s1 = n; - } -@@ -121,13 +121,13 @@ fixup_operands(program &p) - // Special care for x = y - x - value *n = p.new_reg(); - { -- insn_before_inserter ins(b, j); -+ insn_before_inserter ins(b, j, "opt"); - p.mk_mov(ins, n, s0); - } - j->src0 = n; - j->dest = n; - { -- insn_after_inserter ins(b, j); -+ insn_after_inserter ins(b, j, "opt"); - p.mk_mov(ins, d, n); - } - } -@@ -135,7 +135,7 @@ fixup_operands(program &p) - else - { - // Transform { x = y - z } to { x = y; x -= z; } -- insn_before_inserter ins(b, j); -+ insn_before_inserter ins(b, j, "opt"); - p.mk_mov(ins, d, s0); - j->src0 = d; - } -@@ -144,7 +144,7 @@ fixup_operands(program &p) - { - // Comparisons can't have src0 constant. - value *n = p.new_reg(); -- insn_before_inserter ins(b, j); -+ insn_before_inserter ins(b, j, "opt"); - p.mk_mov(ins, n, s0); - j->src0 = n; - } -@@ -293,7 +293,7 @@ reorder_blocks(program &p) - if (t) - { - block *n = p.new_block (); -- insn_append_inserter ins(n); -+ insn_append_inserter ins(n, "opt"); - p.mk_jmp (ins, o); - ordered.push_back (n); - f->redirect_next (n); -@@ -301,7 +301,7 @@ reorder_blocks(program &p) - else - { - delete f; -- insn_after_inserter ins(b, b->last); -+ insn_after_inserter ins(b, b->last, "opt"); - p.mk_jmp (ins, o); - } - } -@@ -780,7 +780,7 @@ spill(unsigned reg, unsigned num_spills, program &p) - // If reg is a source, insert a load before j - if ((src0 && src0->reg_val == reg) || (src1 && src1->reg_val == reg)) - { -- insn_before_inserter ins(b, j); -+ insn_before_inserter ins(b, j, "regalloc"); - new_tmp = p.new_reg(); - - p.mk_ld (ins, BPF_DW, new_tmp, frame, -off); -@@ -795,7 +795,7 @@ spill(unsigned reg, unsigned num_spills, program &p) - // If reg is the destination, insert a store after j - if (dest && dest->reg_val == reg) - { -- insn_after_inserter ins(b, j); -+ insn_after_inserter ins(b, j, "regalloc"); - new_tmp = new_tmp ?: p.new_reg(); - - p.mk_st (ins, BPF_DW, frame, -off, new_tmp); -@@ -935,6 +935,9 @@ post_alloc_cleanup (program &p) - void - program::generate() - { -+#ifdef DEBUG_CODEGEN -+ std::cerr << "DEBUG BEFORE OPT " << *this << std::endl; -+#endif - lower_str_values(*this); - fixup_operands(*this); - thread_jumps(*this); -@@ -942,6 +945,9 @@ program::generate() - reorder_blocks(*this); - reg_alloc(*this); - post_alloc_cleanup(*this); -+#ifdef DEBUG_CODEGEN -+ std::cerr << "DEBUG AFTER OPT " << *this << std::endl; -+#endif - } - - } // namespace bpf -diff --git a/bpf-translate.cxx b/bpf-translate.cxx -index d46dae44a..57a4cb107 100644 ---- a/bpf-translate.cxx -+++ b/bpf-translate.cxx -@@ -310,7 +310,7 @@ bpf_unparser::get_exit_block() - return exit_block; - - block *b = this_prog.new_block(); -- insn_append_inserter ins(b); -+ insn_append_inserter ins(b, "exit_block"); - - this_prog.mk_exit(ins); - -@@ -325,7 +325,7 @@ bpf_unparser::get_ret0_block() - return ret0_block; - - block *b = this_prog.new_block(); -- insn_append_inserter ins(b); -+ insn_append_inserter ins(b, "ret0_block"); - - this_prog.mk_mov(ins, this_prog.lookup_reg(BPF_REG_0), this_prog.new_imm(0)); - b->fallthru = new edge(b, get_exit_block()); -@@ -1166,6 +1166,9 @@ bpf_unparser::emit_asm_opcode (const asm_stmt &stmt, - void - bpf_unparser::visit_embeddedcode (embeddedcode *s) - { -+#ifdef DEBUG_CODEGEN -+ this_ins.notes.push("asm"); -+#endif - std::vector statements; - asm_stmt stmt; - -@@ -1429,6 +1432,10 @@ bpf_unparser::visit_embeddedcode (embeddedcode *s) - it != adjusted_toks.end(); it++) - delete *it; - adjusted_toks.clear(); -+ -+#ifdef DEBUG_CODEGEN -+ this_ins.notes.pop(); // asm -+#endif - } - - void -@@ -2507,6 +2514,10 @@ value * - emit_simple_literal_str(program &this_prog, insn_inserter &this_ins, - value *dest, int ofs, std::string &src, bool zero_pad) - { -+#ifdef DEBUG_CODEGEN -+ this_ins.notes.push("str"); -+#endif -+ - size_t str_bytes = src.size() + 1; - size_t str_words = (str_bytes + 3) / 4; - -@@ -2546,6 +2557,10 @@ emit_simple_literal_str(program &this_prog, insn_inserter &this_ins, - value *out = this_prog.new_reg(); - this_prog.mk_binary(this_ins, BPF_ADD, out, - dest, this_prog.new_imm(ofs)); -+ -+#ifdef DEBUG_CODEGEN -+ this_ins.notes.pop(); // str -+#endif - return out; - } - -@@ -2567,6 +2582,10 @@ bpf_unparser::emit_string_copy(value *dest, int ofs, value *src, bool zero_pad) - dest, ofs, str, zero_pad); - } - -+#ifdef DEBUG_CODEGEN -+ this_ins.notes.push("strcpy"); -+#endif -+ - size_t str_bytes = BPF_MAXSTRINGLEN; - size_t str_words = (str_bytes + 3) / 4; - -@@ -2674,6 +2693,9 @@ bpf_unparser::emit_string_copy(value *dest, int ofs, value *src, bool zero_pad) - value *out = this_prog.new_reg(); - this_prog.mk_binary(this_ins, BPF_ADD, out, - dest, this_prog.new_imm(ofs)); -+#ifdef DEBUG_CODEGEN -+ this_ins.notes.pop(); // strcpy -+#endif - return out; - } - --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0022-standardize-ktime_get_ns-across-lkm-bpf-runtimes.patch b/SOURCES/rhbz1643997.0022-standardize-ktime_get_ns-across-lkm-bpf-runtimes.patch deleted file mode 100644 index 16f658e..0000000 --- a/SOURCES/rhbz1643997.0022-standardize-ktime_get_ns-across-lkm-bpf-runtimes.patch +++ /dev/null @@ -1,284 +0,0 @@ -From 43f6345c9605c0fad57abfe31dda8951f6630ebf Mon Sep 17 00:00:00 2001 -From: "Frank Ch. Eigler" -Date: Tue, 6 Nov 2018 16:26:57 -0500 -Subject: [PATCH 22/32] standardize ktime_get_ns() across lkm, bpf runtimes - -Make sure ktime_get_ns() is available across runtimes. In the case of -bpf, add a userspace helper to implement the function. Add test case. -Add a systemtap.bpf/nobpf.exp test driver, which runs all the -bpf_tests but specifically without "--bpf", in the hope that all those -scripts should run on the normal backend too. PR23866 blocks some of -that at the moment. ---- - stapbpf/bpfinterp.cxx | 13 ++ - tapset/bpf/time.stp | 2 +- - tapset/linux/timestamp_monotonic.stp | 11 ++ - testsuite/systemtap.bpf/bpf_tests/ktime_get_ns.stp | 33 +++++ - testsuite/systemtap.bpf/nonbpf.exp | 152 +++++++++++++++++++++ - 5 files changed, 210 insertions(+), 1 deletion(-) - create mode 100644 testsuite/systemtap.bpf/bpf_tests/ktime_get_ns.stp - create mode 100644 testsuite/systemtap.bpf/nonbpf.exp - -diff --git a/stapbpf/bpfinterp.cxx b/stapbpf/bpfinterp.cxx -index fe6eacc50..13ac8ee71 100644 ---- a/stapbpf/bpfinterp.cxx -+++ b/stapbpf/bpfinterp.cxx -@@ -162,6 +162,16 @@ bpf_sprintf(std::vector &strings, char *fstr, - return reinterpret_cast(strings.back().c_str()); - } - -+uint64_t -+bpf_ktime_get_ns() -+{ -+ struct timespec t; -+ clock_gettime (CLOCK_BOOTTIME, &t); -+ return (t.tv_sec * 1000000000) + t.tv_nsec; -+} -+ -+ -+ - uint64_t - bpf_interpret(size_t ninsns, const struct bpf_insn insns[], - std::vector &map_fds, FILE *output_f) -@@ -374,6 +384,9 @@ bpf_interpret(size_t ninsns, const struct bpf_insn insns[], - case BPF_FUNC_map_delete_elem: - dr = bpf_delete_elem(map_fds[regs[1]], as_ptr(regs[2])); - break; -+ case BPF_FUNC_ktime_get_ns: -+ dr = bpf_ktime_get_ns(); -+ break; - case BPF_FUNC_trace_printk: - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wformat-nonliteral" -diff --git a/tapset/bpf/time.stp b/tapset/bpf/time.stp -index ee615330c..a1c827e73 100644 ---- a/tapset/bpf/time.stp -+++ b/tapset/bpf/time.stp -@@ -12,7 +12,7 @@ - * Description: This function returns the system ktime. - */ - function ktime_get_ns:long () --%{ /* bpf */ /* pure */ /* unprivileged */ /* stable */ -+%{ /* bpf */ /* pure */ /* unprivileged */ - 0x85, 0, 0, 0, 5; /* call BPF_FUNC_ktime_get_ns */ - 0xbf, $$, 0, 0, 0 /* movx $$, r0 */ - %} -diff --git a/tapset/linux/timestamp_monotonic.stp b/tapset/linux/timestamp_monotonic.stp -index 6b6d445de..c8d142369 100644 ---- a/tapset/linux/timestamp_monotonic.stp -+++ b/tapset/linux/timestamp_monotonic.stp -@@ -148,3 +148,14 @@ function local_clock_ms:long () { - function local_clock_s:long () { - return local_clock_ns() / 1000000000; - } -+ -+ -+/** -+ * sfunction ktime_get_ns - Number of nanoseconds since boot -+ * -+ * Description: This function returns the system ktime. -+ */ -+function ktime_get_ns:long () %{ -+ /* pure */ /* unprivileged */ -+ STAP_RETURN ((int64_t) ktime_get_ns()); -+%} -diff --git a/testsuite/systemtap.bpf/bpf_tests/ktime_get_ns.stp b/testsuite/systemtap.bpf/bpf_tests/ktime_get_ns.stp -new file mode 100644 -index 000000000..0b1d98e94 ---- /dev/null -+++ b/testsuite/systemtap.bpf/bpf_tests/ktime_get_ns.stp -@@ -0,0 +1,33 @@ -+global t1, t2, t3 -+ -+probe begin { -+ printf("BEGIN\n") -+ t1 = ktime_get_ns() // bpfinterp.cxx -+} -+ -+probe timer.s(1) { -+ t2 = ktime_get_ns() // kernel bpf - XXX watch if timer.s() moves to userspace -+} -+ -+probe perf.type(1).config(0).hz(1) { -+ t3 = ktime_get_ns() // kernel bpf -+} -+ -+ -+/* -+probe kernel.function("SOMETHING") { # to trigger kernel side bpf func -+ t3 = ktime.get.ns() -+} -+*/ -+ -+ -+probe timer.s(5) { -+ exit() -+} -+ -+probe end { -+ if (t1 > 0 && t2 > 0 && t3 > 0) -+ printf("END PASS\n") -+ else -+ printf("END FAIL\n") -+} -diff --git a/testsuite/systemtap.bpf/nonbpf.exp b/testsuite/systemtap.bpf/nonbpf.exp -new file mode 100644 -index 000000000..35f6a7c99 ---- /dev/null -+++ b/testsuite/systemtap.bpf/nonbpf.exp -@@ -0,0 +1,152 @@ -+# bpf.exp -+# -+# To restrict scripts to test, set the CHECK_ONLY environment variable. -+# For example, to only test the printf and uprobes scripts, run: -+# -+# make installcheck RUNTESTFLAGS="nonbpf.exp" CHECK_ONLY="printf uprobes" -+ -+set testdir "$srcdir/$subdir/bpf_tests" -+ -+# All tests should start by printing "BEGIN". If OUTPUT_STR is "", then -+# the test passes if "END PASS" is read and fails if "END FAIL" is read. Otherwise -+# the test passes when "${OUTPUT_STR}END" is read and fails if END is read without -+# OUTPUT_STR preceeding it. -+proc stapnonbpf_run { TEST_NAME OUTPUT_STR args } { -+ global rc -+ set rc -1 -+ set begin_str "BEGIN" -+ set pass_str [expr { $OUTPUT_STR == "" ? "END PASS" : "${OUTPUT_STR}END" }] -+ set fail_str [expr { $OUTPUT_STR == "" ? "END FAIL" : "END" }] -+ -+ # return codes -+ set pass 0 -+ set fail 1 -+ set bad_output 2 -+ set eof_start 3 -+ set eof_end 4 -+ set timeout_start 5 -+ set timeout_end 6 -+ set invalid_prog 7 -+ set comp_err 8 -+ -+ set cmd [concat stap -v $args] -+ # don't the following: ... $test_file_name could be some transient or leftover file -+ # if [file readable $test_file_name] { lappend cmd $test_file_name } -+ -+ send_log "executing: $cmd\n" -+ eval spawn $cmd -+ set mypid [exp_pid -i $spawn_id] -+ expect { -+ -timeout 30 -+ -re {^WARNING: cannot find module [^\r]*DWARF[^\r]*\r\n} {exp_continue} -+ -re {^WARNING: No unwind data for /.+\r\n} {exp_continue} -+ -re {^Pass\ ([1234]):[^\r]*\ in\ ([0-9]+)usr/([0-9]+)sys/([0-9]+)real\ ms\.\r\n} -+ {set pass$expect_out(1,string) "\t$expect_out(2,string)\t$expect_out(3,string)\t$expect_out(4,string)"; exp_continue} -+ -re {^Pass\ ([34]): using cached [^\r]+\r\n} -+ {set pass$expect_out(1,string) "\t0\t0\t0"; exp_continue} -+ -re {^Passes: via server [^\r]* using [^\r]* in [0-9]+usr/[0-9]+sys/[0-9]+real ms\.\r\n} {exp_continue} -+ -re {^Pass 5: starting run.\r\n} {exp_continue} -+ -re $begin_str { -+ # By default, "expect -re" will match up to 2000 chars. -+ # Increase this to 8K worth of data. -+ exp_match_max 8192 -+ -+ # Avoid PR17274 to propagate -+ set origexpinternal 1 -+ if {"[exp_internal -info]" == "0"} {set origexpinternal 0} -+ #exp_internal 0 -+ -+ expect { -+ -timeout 20 -+ -re $pass_str { -+ set rc $pass -+ } -+ -re $fail_str { -+ set rc $fail -+ } -+ default { -+ set rc $bad_output -+ } -+ timeout { -+ set rc $timeout_end -+ kill -INT -$mypid -+ } -+ eof { set rc $eof_end } -+ } -+ exp_internal $origexpinternal -+ } -+ -re "semantic error:" { set rc $comp_err } -+ timeout { -+ set rc $timeout_start -+ kill -INT -$mypid -+ } -+ eof { set rc $eof_start } -+ } -+ # again for good measure with KILL after 3s -+ kill -INT -$mypid 3 -+ catch close -+ wait -+ return $rc -+} -+ -+proc get_output_str { test } { -+ global res -+ switch $test { -+ printf.stp { set res [string repeat "abcd123456" 3] } -+ sprintf.stp { set res [string repeat "0123456789" 2] } -+ string1.stp { set res {begin\[str0str1str2str3\]probe\[str0str1str2str3\]end\[str0str1str2str3\]} } -+ string2.stp { set res {probe0\[str0str1str2str3\]probe1\[str0str1str2str3\]end\[str0str1str2str3\]} } -+ default { set res "" } -+ } -+ return $res -+} -+ -+if {[info exists env(CHECK_ONLY)]} { -+ set all_files [lsort [glob -nocomplain $testdir/*.stp]] -+ set stap_files "" -+ foreach file $env(CHECK_ONLY) { -+ if {[lsearch $all_files $testdir/$file.stp] >= 0} { -+ set stap_files "$stap_files $testdir/$file.stp" -+ } -+ } -+} else { -+ set stap_files [lsort [glob -nocomplain $testdir/*.stp]] -+} -+ -+foreach file $stap_files { -+ global mypid -+ set mypid 0 -+ set test [file tail $file] -+ if {! [installtest_p]} { untested $test; continue } -+ -+ # create a process for the tests that require one -+ switch $test { -+ uprobes.stp { -+ eval spawn /usr/bin/sleep 20 -+ set mypid [exp_pid -i $spawn_id] -+ } -+ } -+ -+ set output_str [get_output_str $test] -+ verbose -log "Running $file" -+ switch [stapnonbpf_run $test $output_str $file] { -+ 0 { pass $test } -+ 1 { fail "$test incorrect result" } -+ 2 { fail "$test unexpected output" } -+ 3 { fail "$test eof (startup)" } -+ 4 { fail "$test eof (shutdown)" } -+ 5 { fail "$test timeout (startup)" } -+ 6 { fail "$test timeout (startup)" } -+ 7 { fail "$test invalid bpf program" } -+ 8 { fail "$test compilation" } -+ default { fail "$test unknown return value" } -+ } -+ -+ if { $mypid > 0 } { -+ kill -INT -$mypid 3 -+ catch close -+ wait -+ } -+} -+ -+ --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0023-pr23860-verifier-workaround-be-sure-to-delete-all-mo.patch b/SOURCES/rhbz1643997.0023-pr23860-verifier-workaround-be-sure-to-delete-all-mo.patch deleted file mode 100644 index 79b9a58..0000000 --- a/SOURCES/rhbz1643997.0023-pr23860-verifier-workaround-be-sure-to-delete-all-mo.patch +++ /dev/null @@ -1,32 +0,0 @@ -From b43a06011e0a4606504391ffb94762276c95610d Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Wed, 7 Nov 2018 13:07:51 -0500 -Subject: [PATCH 23/32] pr23860 verifier workaround :: be sure to delete all - mov rN,rN - -An apparent bug in the eBPF verifier fails to preserve register state -when MOVing a register to itself, marking rN as 'unknown scalar'. - -Previously bpf-opt.cxx failed to remove spurious MOVs if they were the -final instruction in a basic block. This would fail verification if -the register holds a pointer. ---- - bpf-opt.cxx | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/bpf-opt.cxx b/bpf-opt.cxx -index 904b33b46..8b9a6ea60 100644 ---- a/bpf-opt.cxx -+++ b/bpf-opt.cxx -@@ -909,7 +909,7 @@ post_alloc_cleanup (program &p) - n = j->next; - if (j->is_move() - && j->src1->is_reg() -- && j->dest->reg() == j->src1->reg() && n) -+ && j->dest->reg() == j->src1->reg()) - { - // Delete no-op moves created by partition merging. - insn *p = j->prev; --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0024-PR23860-bugfix-incorrect-comparison-direction-in-str.patch b/SOURCES/rhbz1643997.0024-PR23860-bugfix-incorrect-comparison-direction-in-str.patch deleted file mode 100644 index 8ea990f..0000000 --- a/SOURCES/rhbz1643997.0024-PR23860-bugfix-incorrect-comparison-direction-in-str.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 90b65d0e05faee00c42cd303dd155dd3d228553d Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Fri, 9 Nov 2018 16:19:17 -0500 -Subject: [PATCH 24/32] PR23860 bugfix: incorrect comparison direction in - string_copy() - -(Turns out this branch was flipped and it was a root cause of the havoc.) - -* bpf-translate.cxx (bpf_unparser::emit_string_copy): Correct - direction of JEQ(all_nz,0) jump instruction. ---- - bpf-translate.cxx | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/bpf-translate.cxx b/bpf-translate.cxx -index 57a4cb107..0181380b7 100644 ---- a/bpf-translate.cxx -+++ b/bpf-translate.cxx -@@ -2667,7 +2667,7 @@ bpf_unparser::emit_string_copy(value *dest, int ofs, value *src, bool zero_pad) - } - - this_prog.mk_jcond(this_ins, EQ, all_nz, this_prog.new_imm(0), -- next_block, zero_pad ? block_B[i+1] : join_block); -+ zero_pad ? block_B[i+1] : join_block, next_block); - } - - // XXX: Zero-padding is only used under specific circumstances; --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0025-PR23860-additional-stack-protection-for-strings.patch b/SOURCES/rhbz1643997.0025-PR23860-additional-stack-protection-for-strings.patch deleted file mode 100644 index 65d99c7..0000000 --- a/SOURCES/rhbz1643997.0025-PR23860-additional-stack-protection-for-strings.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 06351f7f372c670a630e7595fcd77913ed05742d Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Thu, 8 Nov 2018 16:40:40 -0500 -Subject: [PATCH 25/32] PR23860: additional stack protection for strings - -Fixes for verifier rejection of some cases requiring string copy, -since the verifier would reject string copy code extending beyond the -end of the string even if it was not reachable. - -* bpf-opt.cxx (alloc_literal_str): make sure the offset for a short - string is at least BPF_MAXSTRINGLEN. -(zero_stack): New function. -(program::generate): Use zero_stack() to zero temporary area and - prevent verifier complaints. -* testsuite/systemtap.bpf/asm_tests/pr23860.stp: New testcase. ---- - bpf-opt.cxx | 32 ++++++++++++++++++++++++++- - testsuite/systemtap.bpf/asm_tests/pr23860.stp | 24 ++++++++++++++++++++ - 2 files changed, 55 insertions(+), 1 deletion(-) - create mode 100644 testsuite/systemtap.bpf/asm_tests/pr23860.stp - -diff --git a/bpf-opt.cxx b/bpf-opt.cxx -index 8b9a6ea60..089dcde55 100644 ---- a/bpf-opt.cxx -+++ b/bpf-opt.cxx -@@ -36,7 +36,19 @@ alloc_literal_str(program &p, insn_inserter &ins, std::string &str) - if (tmp_space + str_bytes > MAX_BPF_STACK) - throw std::runtime_error("string allocation failed due to lack of room on stack"); - -- tmp_space += str_bytes; // TODO: round up for safety? -+ tmp_space += str_bytes; -+ -+#if 1 -+ // XXX PR23860: Passing a short (non-padded) string constant can fail -+ // the verifier, which is not smart enough to determine that accesses -+ // past the end of the string will never occur. To fix this, make sure -+ // the string offset is at least -BPF_MAXSTRINGLEN. -+ // -+ // Not ideal because an unlucky ordering of allocations may waste space. -+ if (tmp_space < BPF_MAXSTRINGLEN) -+ tmp_space = BPF_MAXSTRINGLEN; -+#endif -+ - p.use_tmp_space(tmp_space); - int ofs = -tmp_space; - -@@ -932,19 +944,37 @@ post_alloc_cleanup (program &p) - } - } - -+// XXX PR23860: Passing a short (non-padded) string constant can fail -+// the verifier, which is not smart enough to determine that accesses -+// past the end of the string will never occur. To fix this, start the -+// program with some code to zero out the temporary stack space. -+void -+zero_stack(program &p) -+{ -+ block *entry_block = p.blocks[0]; -+ insn_before_inserter ins(entry_block, entry_block->first, "zero_stack"); -+ value *frame = p.lookup_reg(BPF_REG_10); -+ for (int32_t ofs = -(int32_t)p.max_tmp_space; ofs < 0; ofs += 4) -+ p.mk_st(ins, BPF_W, frame, (int32_t)ofs, p.new_imm(0)); -+} -+ - void - program::generate() - { - #ifdef DEBUG_CODEGEN - std::cerr << "DEBUG BEFORE OPT " << *this << std::endl; - #endif -+ - lower_str_values(*this); -+ zero_stack(*this); -+ - fixup_operands(*this); - thread_jumps(*this); - fold_jumps(*this); - reorder_blocks(*this); - reg_alloc(*this); - post_alloc_cleanup(*this); -+ - #ifdef DEBUG_CODEGEN - std::cerr << "DEBUG AFTER OPT " << *this << std::endl; - #endif -diff --git a/testsuite/systemtap.bpf/asm_tests/pr23860.stp b/testsuite/systemtap.bpf/asm_tests/pr23860.stp -new file mode 100644 -index 000000000..bd3e05f66 ---- /dev/null -+++ b/testsuite/systemtap.bpf/asm_tests/pr23860.stp -@@ -0,0 +1,24 @@ -+function foo:string () -+%{ /* bpf */ /* pure */ /* unprivileged */ /* stable */ -+ 0xbf, $$, "key", -, -; /* mov $$, "key" */ -+%} -+ -+function bar:string () -+{ -+ return "kez" -+} -+ -+global t -+ -+probe begin { -+ t[foo()] = 4 -+ t[bar()] = 6 -+ printf("U t[key]=%d, t[kez]=%d should be 4,6\n", t["key"], t["kez"]) -+} -+ -+probe kernel.function("vfs_read") { -+ t[foo()] = 5 -+ t[bar()] = 7 -+ printf("K t[key]=%d, t[kez]=%d should be 5,7\n", t["key"], t["kez"]) -+ exit() -+} --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0026-PR23860-additional-ugly-stack-clobber-protection-for.patch b/SOURCES/rhbz1643997.0026-PR23860-additional-ugly-stack-clobber-protection-for.patch deleted file mode 100644 index f654c0c..0000000 --- a/SOURCES/rhbz1643997.0026-PR23860-additional-ugly-stack-clobber-protection-for.patch +++ /dev/null @@ -1,222 +0,0 @@ -From a7605f298f8d823429b8cfd264bd28c3bd345eb5 Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Fri, 9 Nov 2018 14:36:19 -0500 -Subject: [PATCH 26/32] PR23860: additional ugly stack/clobber protection for - strings - -In addition to prior commit, emit_string_copy() does not work for -overlapping source/destination. So, make sure strings are not -allocated in a way which overlaps map key/value arguments. - -This increases space pressure, inducing a couple of bpf-asm.exp -testcase failures. - -* bpf-internal.h (value::format_str): New flag. -(value::value): Take format_str flag. -(value::mk_str): Take format_str flag. -(program::format_map): New field, caches format_str separately. -(program::new_str): Take format_str flag. -* bpf-base.cxx (program::new_str): Cache format_str separately. -* bpf-opt.cxx (alloc_literal_str): Store non-format str in lower half. -* bpf-translate.cxx (emit_string_copy): Comment -- doesn't support overlap. -(emit_string_copy): DEBUG_CODEGEN -- identify if zero-padding was done. -(emit_print_format): Set format_str flag. ---- - bpf-base.cxx | 13 ++++++++----- - bpf-internal.h | 15 +++++++++++---- - bpf-opt.cxx | 35 ++++++++++++++++++++++++----------- - bpf-translate.cxx | 7 +++++-- - 4 files changed, 48 insertions(+), 22 deletions(-) - -diff --git a/bpf-base.cxx b/bpf-base.cxx -index 5d132bcd1..b19b69133 100644 ---- a/bpf-base.cxx -+++ b/bpf-base.cxx -@@ -657,14 +657,17 @@ program::new_imm(int64_t i) - } - - value * --program::new_str(std::string str) -+program::new_str(std::string str, bool format_str) - { -- auto old = str_map.find(str); -- if (old != str_map.end()) -+ std::unordered_map& m = str_map; -+ if (format_str) m = format_map; -+ -+ auto old = m.find(str); -+ if (old != m.end()) - return old->second; - -- value *v = new value(value::mk_str(str)); -- auto ok = str_map.insert(std::pair(str, v)); -+ value *v = new value(value::mk_str(str, format_str)); -+ auto ok = m.insert(std::pair(str, v)); - assert(ok.second); - return v; - } -diff --git a/bpf-internal.h b/bpf-internal.h -index 75fefb769..f97501d7d 100644 ---- a/bpf-internal.h -+++ b/bpf-internal.h -@@ -78,18 +78,24 @@ struct value - int64_t imm_val; - std::string str_val; - -- value(value_type t = UNINIT, regno r = noreg, int64_t c = 0, std::string s = "") -- : type(t), reg_val(r), imm_val(c), str_val(s) -+ bool format_str; // for str_val -+ -+ value(value_type t = UNINIT, regno r = noreg, int64_t c = 0, -+ std::string s = "", bool format_str = false) -+ : type(t), reg_val(r), imm_val(c), str_val(s), format_str(format_str) - { } - - static value mk_imm(int64_t i) { return value(IMM, noreg, i); } -- static value mk_str(std::string s) { return value(STR, noreg, 0, s); } -+ static value mk_str(std::string s, bool format_str = false) { -+ return value(STR, noreg, 0, s, format_str); -+ } - static value mk_reg(regno r) { return value(TMPREG, r); } - static value mk_hardreg(regno r) { return value(HARDREG, r); } - - bool is_reg() const { return type >= HARDREG; } - bool is_imm() const { return type == IMM; } - bool is_str() const { return type == STR; } -+ bool is_format() const { assert(is_str()); return format_str; } - - regno reg() const { assert(is_reg()); return reg_val; } - int64_t imm() const { assert(is_imm()); return imm_val; } -@@ -262,12 +268,13 @@ struct program - // Store at most one of each IMM and STR value: - std::unordered_map imm_map; - std::unordered_map str_map; -+ std::unordered_map format_map; - - regno max_reg() const { return reg_vals.size() + MAX_BPF_REG; } - value *lookup_reg(regno r); - value *new_reg(); - value *new_imm(int64_t); -- value *new_str(std::string); -+ value *new_str(std::string, bool format_str = false); - - // The BPF local stack is [0, -512] indexed off BPF_REG_10. - // The translator has dibs on the low bytes, [0, -max_tmp_space], -diff --git a/bpf-opt.cxx b/bpf-opt.cxx -index 089dcde55..f3aa5c462 100644 ---- a/bpf-opt.cxx -+++ b/bpf-opt.cxx -@@ -19,38 +19,51 @@ namespace bpf { - - // Allocate space on the stack and store a string literal in that space: - static value * --alloc_literal_str(program &p, insn_inserter &ins, std::string &str) -+alloc_literal_str(program &p, insn_inserter &ins, value *s) - { -+ std::string str = s->str(); -+ -+ size_t str_bytes = str.size() + 1; -+ str_bytes += 4 - str_bytes % 4; // write aligned words to avoid garbage data -+ -+ int ofs; size_t tmp_space; -+ - // Append the string to existing temporary data. - // - // TODO: This could produce significant space limitations. - // A better solution would be to integrate with the - // register allocator and reclaim the space after - // the string literal is no longer live. -- size_t tmp_space = p.max_tmp_space; -+ tmp_space = p.max_tmp_space; - tmp_space += 4 - tmp_space % 4; // write aligned words to avoid verifier error - p.use_tmp_space(tmp_space); - -- size_t str_bytes = str.size() + 1; -- str_bytes += 4 - str_bytes % 4; // write aligned words to avoid garbage data - if (tmp_space + str_bytes > MAX_BPF_STACK) - throw std::runtime_error("string allocation failed due to lack of room on stack"); - - tmp_space += str_bytes; - - #if 1 -+ // The following aren't ideal because an unlucky ordering of -+ // allocation requests will waste additional space. -+ - // XXX PR23860: Passing a short (non-padded) string constant can fail - // the verifier, which is not smart enough to determine that accesses - // past the end of the string will never occur. To fix this, make sure - // the string offset is at least -BPF_MAXSTRINGLEN. -- // -- // Not ideal because an unlucky ordering of allocations may waste space. -- if (tmp_space < BPF_MAXSTRINGLEN) -- tmp_space = BPF_MAXSTRINGLEN; -+ //if (!s->is_format() && tmp_space < BPF_MAXSTRINGLEN) -+ // tmp_space = BPF_MAXSTRINGLEN; -+ -+ // TODO PR23860: An even uglier workaround for emit_string_copy() -+ // overlapping source and destination regions. Only do this for -+ // non-format strings, as format strings are not manipulated by the -+ // eBPF program. -+ if (!s->is_format() && tmp_space < BPF_MAXSTRINGLEN * 2 + str_bytes) -+ tmp_space = BPF_MAXSTRINGLEN * 2 + str_bytes; - #endif - - p.use_tmp_space(tmp_space); -- int ofs = -tmp_space; -+ ofs = -tmp_space; - - value *frame = p.lookup_reg(BPF_REG_10); - value *out = emit_simple_literal_str(p, ins, frame, ofs, str, false /* don't zero pad */); -@@ -73,7 +86,7 @@ lower_str_values(program &p) - { - insn_before_inserter ins(b, j, "str"); - std::string str0 = s0->str(); -- value *new_s0 = alloc_literal_str(p, ins, str0); -+ value *new_s0 = alloc_literal_str(p, ins, s0); - j->src0 = new_s0; - } - -@@ -82,7 +95,7 @@ lower_str_values(program &p) - { - insn_before_inserter ins(b, j, "str"); - std::string str1 = s1->str(); -- value *new_s1 = alloc_literal_str(p, ins, str1); -+ value *new_s1 = alloc_literal_str(p, ins, s1); - j->src1 = new_s1; - } - } -diff --git a/bpf-translate.cxx b/bpf-translate.cxx -index 0181380b7..20cd47032 100644 ---- a/bpf-translate.cxx -+++ b/bpf-translate.cxx -@@ -2568,6 +2568,9 @@ emit_simple_literal_str(program &this_prog, insn_inserter &this_ins, - // dest[+ofs] in 4-byte chunks, with optional zero-padding up to - // BPF_MAXSTRINGLEN. - // -+// TODO (PR23860): This code does not work when the source and target -+// regions overlap. -+// - // ??? Could use 8-byte chunks if we're starved for instruction count. - // ??? Endianness of the target may come into play here. - value * -@@ -2583,7 +2586,7 @@ bpf_unparser::emit_string_copy(value *dest, int ofs, value *src, bool zero_pad) - } - - #ifdef DEBUG_CODEGEN -- this_ins.notes.push("strcpy"); -+ this_ins.notes.push(zero_pad ? "strcpy_zero_pad" : "strcpy"); - #endif - - size_t str_bytes = BPF_MAXSTRINGLEN; -@@ -2866,7 +2869,7 @@ bpf_unparser::emit_print_format (const std::string& format, - // bpf program stack. This is handled by bpf-opt.cxx lowering STR values. - size_t format_bytes = format.size() + 1; - this_prog.mk_mov(this_ins, this_prog.lookup_reg(BPF_REG_1), -- this_prog.new_str(format)); -+ this_prog.new_str(format, true /*format_str*/)); - emit_mov(this_prog.lookup_reg(BPF_REG_2), this_prog.new_imm(format_bytes)); - for (size_t i = 0; i < nargs; ++i) - emit_mov(this_prog.lookup_reg(BPF_REG_3 + i), actual[i]); --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0027-PR23860-reduce-stack-pressure-from-format-strings.patch b/SOURCES/rhbz1643997.0027-PR23860-reduce-stack-pressure-from-format-strings.patch deleted file mode 100644 index 60beb93..0000000 --- a/SOURCES/rhbz1643997.0027-PR23860-reduce-stack-pressure-from-format-strings.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 59ec363d7236d92f896135ef8fe85433d6f1995e Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Fri, 9 Nov 2018 16:24:09 -0500 -Subject: [PATCH 27/32] PR23860: reduce stack pressure from format strings - -Reduce stack pressure created by the earlier commits by allocating -format strings in a predictable location in the top half of the stack -[-BPF_MAXSTRINGLEN*2..0) as long as they fit in there. This works -since only one format string is active at a time and no ordinary -strings are being allocated in that region of the stack now. - -* bpf-opt.cxx (alloc_literal_str): Store format_str in top half. ---- - bpf-opt.cxx | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/bpf-opt.cxx b/bpf-opt.cxx -index f3aa5c462..5c7acb6b9 100644 ---- a/bpf-opt.cxx -+++ b/bpf-opt.cxx -@@ -27,6 +27,16 @@ alloc_literal_str(program &p, insn_inserter &ins, value *s) - str_bytes += 4 - str_bytes % 4; // write aligned words to avoid garbage data - - int ofs; size_t tmp_space; -+ if (s->is_format() && str_bytes <= BPF_MAXSTRINGLEN * 2) -+ { -+ // PR23068 workaround mitigation to reduce stack pressure: -+ // -+ // Store format strings in the top of the stack, since at most -+ // one printf() operation is prepared at a time and other string -+ // values will not be stored in that area now. -+ ofs = -str_bytes; -+ goto write_string; -+ } - - // Append the string to existing temporary data. - // -@@ -65,6 +75,7 @@ alloc_literal_str(program &p, insn_inserter &ins, value *s) - p.use_tmp_space(tmp_space); - ofs = -tmp_space; - -+ write_string: - value *frame = p.lookup_reg(BPF_REG_10); - value *out = emit_simple_literal_str(p, ins, frame, ofs, str, false /* don't zero pad */); - return out; --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0028-testcase-for-PR23875.patch b/SOURCES/rhbz1643997.0028-testcase-for-PR23875.patch deleted file mode 100644 index b2de726..0000000 --- a/SOURCES/rhbz1643997.0028-testcase-for-PR23875.patch +++ /dev/null @@ -1,40 +0,0 @@ -From c3023bef537648b282f266878ea8de7a350b3a45 Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Fri, 9 Nov 2018 16:42:21 -0500 -Subject: [PATCH 28/32] testcase for PR23875 - -This triggers a 'stack smashing' error in the userspace interpreter. - -* testsuite/systemtap.bpf/bpf_tests/pr23875.stp: New testcase. ---- - testsuite/systemtap.bpf/bpf_tests/pr23875.stp | 18 ++++++++++++++++++ - 1 file changed, 18 insertions(+) - create mode 100644 testsuite/systemtap.bpf/bpf_tests/pr23875.stp - -diff --git a/testsuite/systemtap.bpf/bpf_tests/pr23875.stp b/testsuite/systemtap.bpf/bpf_tests/pr23875.stp -new file mode 100644 -index 000000000..a31f1d087 ---- /dev/null -+++ b/testsuite/systemtap.bpf/bpf_tests/pr23875.stp -@@ -0,0 +1,18 @@ -+global t -+ -+probe begin { -+ printf("BEGIN\n") -+} -+ -+probe kernel.function("vfs_read") { -+ t["key"] = 6 -+ exit() -+} -+ -+probe end { -+ c = 0 -+ foreach (k in t) -+ c++ -+ printf("%d\n", c) -+ printf("END PASS\n") -+} --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0029-PR23860-bpf_interpret-NEG-should-not-fall-through-to.patch b/SOURCES/rhbz1643997.0029-PR23860-bpf_interpret-NEG-should-not-fall-through-to.patch deleted file mode 100644 index 70f91dd..0000000 --- a/SOURCES/rhbz1643997.0029-PR23860-bpf_interpret-NEG-should-not-fall-through-to.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 6adc7dbeccecff18357751b9eecfa232ee8a8172 Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Tue, 13 Nov 2018 11:42:46 -0500 -Subject: [PATCH 29/32] PR23860 bpf_interpret() :: NEG should not fall through - to DIV - ---- - stapbpf/bpfinterp.cxx | 26 ++++++++++++++++++-------- - 1 file changed, 18 insertions(+), 8 deletions(-) - -diff --git a/stapbpf/bpfinterp.cxx b/stapbpf/bpfinterp.cxx -index 13ac8ee71..2a90c24c9 100644 ---- a/stapbpf/bpfinterp.cxx -+++ b/stapbpf/bpfinterp.cxx -@@ -254,18 +254,23 @@ bpf_interpret(size_t ninsns, const struct bpf_insn insns[], - case BPF_ALU64 | BPF_MOV | BPF_K: dr = s1; break; - case BPF_ALU64 | BPF_ARSH | BPF_X: - case BPF_ALU64 | BPF_ARSH | BPF_K: dr = (int64_t)dr >> s1; break; -- case BPF_ALU64 | BPF_NEG: dr = -sr; -- /* Fallthrough */ -+ case BPF_ALU64 | BPF_NEG: dr = -sr; break; - case BPF_ALU64 | BPF_DIV | BPF_X: - case BPF_ALU64 | BPF_DIV | BPF_K: - if (s1 == 0) -- return 0; -+ { -+ // TODO: Signal a proper error. -+ return 0; -+ } - dr /= s1; - break; - case BPF_ALU64 | BPF_MOD | BPF_X: - case BPF_ALU64 | BPF_MOD | BPF_K: - if (s1 == 0) -- return 0; -+ { -+ // TODO: Signal a proper error. -+ return 0; -+ } - dr %= s1; - break; - -@@ -289,18 +294,23 @@ bpf_interpret(size_t ninsns, const struct bpf_insn insns[], - case BPF_ALU | BPF_MOV | BPF_K: dr = (uint32_t)s1; break; - case BPF_ALU | BPF_ARSH | BPF_X: - case BPF_ALU | BPF_ARSH | BPF_K: dr = (int32_t)dr >> s1; break; -- case BPF_ALU | BPF_NEG: dr = -(uint32_t)sr; -- /* Fallthrough */ -+ case BPF_ALU | BPF_NEG: dr = -(uint32_t)sr; break; - case BPF_ALU | BPF_DIV | BPF_X: - case BPF_ALU | BPF_DIV | BPF_K: - if ((uint32_t)s1 == 0) -- return 0; -+ { -+ // TODO: Signal a proper error. -+ return 0; -+ } - dr = (uint32_t)dr / (uint32_t)s1; - break; - case BPF_ALU | BPF_MOD | BPF_X: - case BPF_ALU | BPF_MOD | BPF_K: - if ((uint32_t)s1 == 0) -- return 0; -+ { -+ // TODO: Signal a proper error. -+ return 0; -+ } - dr = (uint32_t)dr % (uint32_t)s1; - break; - --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0030-PR23875-bpf.exp-fail-testcase-on-stack-smashing.patch b/SOURCES/rhbz1643997.0030-PR23875-bpf.exp-fail-testcase-on-stack-smashing.patch deleted file mode 100644 index c8a4f72..0000000 --- a/SOURCES/rhbz1643997.0030-PR23875-bpf.exp-fail-testcase-on-stack-smashing.patch +++ /dev/null @@ -1,26 +0,0 @@ -From d3a33cd7b8c1b0bfe236bdea2bde83c9c6a83c05 Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Tue, 13 Nov 2018 12:27:05 -0500 -Subject: [PATCH 30/32] PR23875 bpf.exp: fail testcase on 'stack smashing' - ---- - testsuite/systemtap.bpf/bpf.exp | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/testsuite/systemtap.bpf/bpf.exp b/testsuite/systemtap.bpf/bpf.exp -index e8e94bf19..3f32b6c79 100644 ---- a/testsuite/systemtap.bpf/bpf.exp -+++ b/testsuite/systemtap.bpf/bpf.exp -@@ -58,6 +58,9 @@ proc stapbpf_run { TEST_NAME OUTPUT_STR args } { - - expect { - -timeout 20 -+ -re "stack smashing detected" { -+ set rc $bad_output -+ } - -re $pass_str { - set rc $pass - } --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0031-PR23875-another-testcase-that-loops-indefinitely.patch b/SOURCES/rhbz1643997.0031-PR23875-another-testcase-that-loops-indefinitely.patch deleted file mode 100644 index 56aa420..0000000 --- a/SOURCES/rhbz1643997.0031-PR23875-another-testcase-that-loops-indefinitely.patch +++ /dev/null @@ -1,36 +0,0 @@ -From ed0fac0c88da94f40f826a41cc87d0d9d7620f34 Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Tue, 13 Nov 2018 13:07:52 -0500 -Subject: [PATCH 31/32] PR23875: another testcase that loops indefinitely - ---- - testsuite/systemtap.bpf/bpf_tests/pr23875_loop.stp | 11 +++++++++++ - .../bpf_tests/{pr23875.stp => pr23875_smash.stp} | 0 - 2 files changed, 11 insertions(+) - create mode 100644 testsuite/systemtap.bpf/bpf_tests/pr23875_loop.stp - rename testsuite/systemtap.bpf/bpf_tests/{pr23875.stp => pr23875_smash.stp} (100%) - -diff --git a/testsuite/systemtap.bpf/bpf_tests/pr23875_loop.stp b/testsuite/systemtap.bpf/bpf_tests/pr23875_loop.stp -new file mode 100644 -index 000000000..5912ebf8c ---- /dev/null -+++ b/testsuite/systemtap.bpf/bpf_tests/pr23875_loop.stp -@@ -0,0 +1,11 @@ -+global t -+ -+probe begin { -+ println("BEGIN") -+ t["key"] = 6 -+} -+ -+probe end { -+ foreach (k in t) printf("%s -> %d\n", k, t[k]) -+ println("END PASS") -+} -diff --git a/testsuite/systemtap.bpf/bpf_tests/pr23875.stp b/testsuite/systemtap.bpf/bpf_tests/pr23875_smash.stp -similarity index 100% -rename from testsuite/systemtap.bpf/bpf_tests/pr23875.stp -rename to testsuite/systemtap.bpf/bpf_tests/pr23875_smash.stp --- -2.14.5 - diff --git a/SOURCES/rhbz1643997.0032-PR23875-bpf_unparser-visit_foreach_loop-temporarily-.patch b/SOURCES/rhbz1643997.0032-PR23875-bpf_unparser-visit_foreach_loop-temporarily-.patch deleted file mode 100644 index 6001e56..0000000 --- a/SOURCES/rhbz1643997.0032-PR23875-bpf_unparser-visit_foreach_loop-temporarily-.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 6fd1813950d708c5b94ed155213a7b9c84b7fbfc Mon Sep 17 00:00:00 2001 -From: Serhei Makarov -Date: Tue, 13 Nov 2018 13:13:14 -0500 -Subject: [PATCH 32/32] PR23875 bpf_unparser::visit_foreach_loop(): temporarily - disable string key iteration - ---- - bpf-translate.cxx | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/bpf-translate.cxx b/bpf-translate.cxx -index 20cd47032..0f35e0d3f 100644 ---- a/bpf-translate.cxx -+++ b/bpf-translate.cxx -@@ -1532,6 +1532,10 @@ bpf_unparser::visit_foreach_loop(foreach_loop* s) - throw SEMANTIC_ERROR(_("unknown type"), s->base->tok); - vardecl *arraydecl = a->referent; - -+ // TODO PR23875: foreach should handle string keys -+ if (arraydecl->index_types[0] != pe_long) -+ throw SEMANTIC_ERROR(_("unhandled string index type"), s->tok); -+ - auto g = glob.globals.find(arraydecl); - if (g == glob.globals.end()) - throw SEMANTIC_ERROR(_("unknown array"), arraydecl->tok); --- -2.14.5 - diff --git a/SOURCES/rhbz1656795.patch b/SOURCES/rhbz1656795.patch deleted file mode 100644 index 65f6f74..0000000 --- a/SOURCES/rhbz1656795.patch +++ /dev/null @@ -1,105 +0,0 @@ -commit aacee6563b7fd835b9a21e4ae5a0b4f7f743c7ef -Author: Martin Cermak -Date: Thu Dec 6 13:52:20 2018 +0100 - - Make sysc_bdflush.stp compatible with 4.17+ kernels. - - The bdflush syscall itself appears to be obsolete since 2.6, - but this way we at least won't end up with pass 1 "resolution - failed in alias expansion builder" when randomly probing for it. - There is an old customer rh bz 544960 related to bdflush. - -diff --git a/tapset/linux/sysc_bdflush.stp b/tapset/linux/sysc_bdflush.stp -index 0798964..48a04b9 100644 ---- a/tapset/linux/sysc_bdflush.stp -+++ b/tapset/linux/sysc_bdflush.stp -@@ -11,6 +11,12 @@ - argstr = sprintf("%d, %s", func, data_str) - %) - -+@define _SYSCALL_BDFLUSH_REGARGS -+%( -+ func = int_arg(1) -+ data = long_arg(2) -+%) -+ - probe syscall.bdflush = dw_syscall.bdflush !, nd_syscall.bdflush ? {} - probe syscall.bdflush.return = dw_syscall.bdflush.return !, nd_syscall.bdflush.return ? {} - -@@ -35,20 +41,72 @@ probe dw_syscall.bdflush.return = kernel.function("sys_bdflush").return ? - - # nd_bdflush _____________________________________________________ - --probe nd_syscall.bdflush = kprobe.function("sys_bdflush") ? -+ -+probe nd_syscall.bdflush = nd1_syscall.bdflush!, nd2_syscall.bdflush!, tp_syscall.bdflush -+{ -+} -+ -+probe nd1_syscall.bdflush = kprobe.function("sys_bdflush") ? - { - @_SYSCALL_BDFLUSH_NAME - asmlinkage() -- func = int_arg(1) -- data = long_arg(2) -+ @_SYSCALL_BDFLUSH_REGARGS - if ((func >= 2) && (func % 2 == 0)) - data_str = sprintf("%p", data) - else - data_str = sprintf("%d", data) - @_SYSCALL_BDFLUSH_ARGSTR - } --probe nd_syscall.bdflush.return = kprobe.function("sys_bdflush").return ? -+ -+/* kernel 4.17+ */ -+probe nd2_syscall.bdflush = kprobe.function(@arch_syscall_prefix "sys_bdflush") ? -+{ -+ @_SYSCALL_BDFLUSH_NAME -+ asmlinkage() -+ @_SYSCALL_BDFLUSH_REGARGS -+ if ((func >= 2) && (func % 2 == 0)) -+ data_str = sprintf("%p", data) -+ else -+ data_str = sprintf("%d", data) -+ @_SYSCALL_BDFLUSH_ARGSTR -+} -+ -+/* kernel 3.5+, but undesirable because it affects all syscalls */ -+probe tp_syscall.bdflush = kernel.trace("sys_enter") -+{ -+ __set_syscall_pt_regs($regs) -+ @__syscall_compat_gate(@const("__NR_bdflush"), @const("__NR_compat_bdflush")) -+ @_SYSCALL_BDFLUSH_NAME -+ @_SYSCALL_BDFLUSH_REGARGS -+ if ((func >= 2) && (func % 2 == 0)) -+ data_str = sprintf("%p", data) -+ else -+ data_str = sprintf("%d", data) -+ @_SYSCALL_BDFLUSH_ARGSTR -+} -+ -+probe nd_syscall.bdflush.return = nd1_syscall.bdflush.return!, nd2_syscall.bdflush.return!, tp_syscall.bdflush.return -+{ -+} -+ -+probe nd1_syscall.bdflush.return = kprobe.function("sys_bdflush").return ? -+{ -+ @_SYSCALL_BDFLUSH_NAME -+ @SYSC_RETVALSTR(returnval()) -+} -+ -+/* kernel 4.17+ */ -+probe nd2_syscall.bdflush.return = kprobe.function(@arch_syscall_prefix "sys_bdflush").return ? - { - @_SYSCALL_BDFLUSH_NAME - @SYSC_RETVALSTR(returnval()) - } -+ -+/* kernel 3.5+, but undesirable because it affects all syscalls */ -+probe tp_syscall.bdflush.return = kernel.trace("sys_exit") -+{ -+ __set_syscall_pt_regs($regs) -+ @__syscall_compat_gate(@const("__NR_bdflush"), @const("__NR_compat_bdflush")) -+ @_SYSCALL_BDFLUSH_NAME -+ @SYSC_RETVALSTR($ret) -+} diff --git a/SOURCES/rhbz1657186.patch b/SOURCES/rhbz1657186.patch deleted file mode 100644 index 41aa076..0000000 --- a/SOURCES/rhbz1657186.patch +++ /dev/null @@ -1,64 +0,0 @@ -commit 8bc64034509474bee3fb7996b2a9e74c8bc27281 -Author: Frank Ch. Eigler -Date: Fri Oct 19 17:36:04 2018 -0400 - - nfsd tapset: adapt nfsd.proc4.read probe to different kernel versions - - Here too an if(@defined($u)) is appropriate, just like in the .write case. - -diff --git a/tapset/linux/nfsd.stp b/tapset/linux/nfsd.stp -index 2fe9b0f..674e3e3 100644 ---- a/tapset/linux/nfsd.stp -+++ b/tapset/linux/nfsd.stp -@@ -567,10 +567,17 @@ probe nfsd.proc4.read = kernel.function("nfsd4_read").call !, - version = 4 - fh = & @nfsd4_compound_state($cstate)->current_fh - -- count = $read->rd_length -- offset = $read->rd_offset -- vec = $rqstp->rq_vec -- vlen = $read->rd_vlen -+ if (@defined($u)) { -+ count = $u->read->rd_length -+ offset = $u->read->rd_offset -+ vec = $rqstp->rq_vec -+ vlen = $u->read->rd_vlen -+ } else { -+ count = $read->rd_length -+ offset = $read->rd_offset -+ vec = $rqstp->rq_vec -+ vlen = $read->rd_vlen -+ } - - uid = __rqstp_uid($rqstp) - gid = __rqstp_gid($rqstp) - -commit 4e81610ae8c233d876f378cca8374e34cc2ee0e8 -Author: Frank Ch. Eigler -Date: Fri Oct 19 19:31:31 2018 -0400 - - nfsd tapset: adapt nfsd.proc4.commit probe to different kernel versions - - Here too an if(@defined($u)) is appropriate, just like in - every other case. Audited remainder. - -diff --git a/tapset/linux/nfsd.stp b/tapset/linux/nfsd.stp -index 674e3e3..aa04f24 100644 ---- a/tapset/linux/nfsd.stp -+++ b/tapset/linux/nfsd.stp -@@ -852,8 +852,13 @@ probe nfsd.proc4.commit = kernel.function("nfsd4_commit").call !, - proto = $rqstp->rq_prot - version = 4 - fh = & @nfsd4_compound_state($cstate)->current_fh -- count = $commit->co_count -- offset = $commit->co_offset -+ if (@defined($u)) { -+ count = $u->commit->co_count -+ offset = $u->commit->co_offset -+ } else { -+ count = $commit->co_count -+ offset = $commit->co_offset -+ } - - uid = __rqstp_uid($rqstp) - gid = __rqstp_gid($rqstp) diff --git a/SOURCES/rhbz1657857.patch b/SOURCES/rhbz1657857.patch deleted file mode 100644 index f1a1ced..0000000 --- a/SOURCES/rhbz1657857.patch +++ /dev/null @@ -1,66 +0,0 @@ -commit 75640f70daa0e8bab73e398113ea755e23eab887 -Author: William Cohen -Date: Mon Nov 12 17:24:44 2018 -0500 - - Adjust the periodic.stp example to work with newer Linux kernels - - The data field in the timer_list struct was removed in newer kernels. - The various functions executed when a timer expires now use - container_of macros to find the struct that the timer_list was - embedded in. The periodic.stp script has been modified to use - container_of when the data field is not available. - -diff --git a/testsuite/systemtap.examples/profiling/periodic.stp b/testsuite/systemtap.examples/profiling/periodic.stp -index 3b41981c0..f18f18399 100755 ---- a/testsuite/systemtap.examples/profiling/periodic.stp -+++ b/testsuite/systemtap.examples/profiling/periodic.stp -@@ -7,7 +7,7 @@ - # - # stap --all-modules periodic.stp - --global last_expire, period, funct, data -+global last_expire, period, funct, data, proc_info, delayed_work_info - - probe kernel.trace("timer_expire_entry") - { -@@ -17,7 +17,9 @@ probe kernel.trace("timer_expire_entry") - elapsed = new_expire - old_expire - period[$timer] <<< elapsed - funct[$timer] = $timer->function -- data[$timer] = $timer->data -+ data[$timer] = @defined($timer->data) ? $timer->data : 0 -+ proc_info[$timer] = @defined($timer->data) ? 0 : @container_of($timer, "struct process_timer", timer)->task -+ delayed_work_info[$timer] = @defined($timer->data) ? 0 : & @container_of($timer, "struct delayed_work", timer) - } - last_expire[$timer] = new_expire - } -@@ -29,14 +31,16 @@ function output() - foreach([timer] in period-) { - fname = symname(funct[timer]) - if (fname == "process_timeout") { -+ ptr = (data[timer] ? data[timer] : proc_info[timer]) - fname = sprintf("%s(%d)", -- kernel_string_n(@cast(data[timer], "struct task_struct", "kernel")->comm, 16), -- @cast(data[timer], "struct task_struct", "kernel")->pid) -+ kernel_string_n(@cast(ptr, "struct task_struct", "kernel")->comm, 16), -+ @cast(ptr, "struct task_struct", "kernel")->pid) - type="process" - } else if (fname == "delayed_work_timer_fn") { -- faddr = @defined(@cast(data[timer], "struct delayed_work", "kernel")->work->func) -- ? @cast(data[timer], "struct delayed_work", "kernel")->work->func -- : @cast(data[timer], "struct work_struct", "kernel")->func -+ ptr = (data[timer] ? data[timer] : delayed_work_info[timer]) -+ faddr = @defined(@cast(ptr, "struct delayed_work", "kernel")->work->func) -+ ? @cast(ptr, "struct delayed_work", "kernel")->work->func -+ : @cast(ptr, "struct work_struct", "kernel")->func - fname = sprintf("%s", symname(faddr)) - type="work_q" - } else { -@@ -68,5 +72,7 @@ probe timer.s($1) - delete period - delete funct - delete data -+ delete proc_info -+ delete delayed_work_info - } - %) diff --git a/SOURCES/rhbz1657909.patch b/SOURCES/rhbz1657909.patch deleted file mode 100644 index dae906f..0000000 --- a/SOURCES/rhbz1657909.patch +++ /dev/null @@ -1,34 +0,0 @@ -commit f6d68366654176541487a8916c3b61c5b1207736 -Author: William Cohen -Date: Mon Nov 19 14:23:15 2018 -0500 - - Adjust the vfs_open to provide cred variable with 4.18 kernels - - The kernel's git commit ae2bb293a3e8adbc54d08cede5afc22929030c03 - removed the cred argument from the vfs_open. Thus, there is no $cred - target variable available. This missing target variable lives on as a - field in the $file target variable. The patch makes the tapset use - that field if the $cred target variable is not available. Fixing this - allows the slowvfs.stp example to work with newer linux 4.18 kernels. - -diff --git a/tapset/linux/vfs.stp b/tapset/linux/vfs.stp -index 1fe71ae..7505dfa 100644 ---- a/tapset/linux/vfs.stp -+++ b/tapset/linux/vfs.stp -@@ -1296,7 +1296,7 @@ probe vfs.open = kernel.function("vfs_open") ? - { - name = "vfs.open" - path = $path -- cred = $cred -+ cred = @defined($cred) ? $cred : $file->f_cred - pathname = fullpath_struct_path($path) - argstr = sprintf("%s, %p", pathname, $cred) - } -@@ -1311,6 +1311,6 @@ probe vfs.open.return = kernel.function("vfs_open").return ? - error_str = error ? errno_str(error) : "" - - path = @entry($path) -- cred = @entry($cred) -+ cred = @entry(@defined($cred) ? $cred : $file->f_cred) - pathname = fullpath_struct_path(@entry($path)) - } diff --git a/SOURCES/rhbz1732173.patch b/SOURCES/rhbz1732173.patch new file mode 100644 index 0000000..3466649 --- /dev/null +++ b/SOURCES/rhbz1732173.patch @@ -0,0 +1,32 @@ +commit 7be7af0fda3633cd19e499617834cf4a5f51dd55 +Author: William Cohen +Date: Tue Jul 23 14:24:14 2019 -0400 + + Fix aarch64 to properly access arguments for wrapped syscalls + + Linux 4.18 added wrappers for aarch64 syscalls that pass a pointer to + a struct pt_regs holding the values for the actual arguments. The + syscall tapsets initialize CONTEXT->sregs to point at this data + structure. However, the aarch64 specific register access code was + using the CONTEXT->kregs and just getting the processor register state + when the kprobe triggered rather than the expected arguments in the + data structure being passed into the syscall. The aarch64 specific + register code now gets the syscall arguments from the correct pt_regs + structure. + +diff --git a/tapset/arm64/registers.stp b/tapset/arm64/registers.stp +index b2e5649..8773df2 100644 +--- a/tapset/arm64/registers.stp ++++ b/tapset/arm64/registers.stp +@@ -58,7 +58,10 @@ function uarch_bytes:long() { + function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ + long value; + struct pt_regs *regs; +- regs = (CONTEXT->user_mode_p ? CONTEXT->uregs : CONTEXT->kregs); ++ if (CONTEXT->sregs) ++ regs = CONTEXT->sregs; ++ else ++ regs = (CONTEXT->user_mode_p ? CONTEXT->uregs : CONTEXT->kregs); + if (!regs) { + CONTEXT->last_error = "No registers available in this context"; + return; diff --git a/SPECS/systemtap.spec b/SPECS/systemtap.spec index faefc0e..fdd5b0c 100644 --- a/SPECS/systemtap.spec +++ b/SPECS/systemtap.spec @@ -4,7 +4,7 @@ %{!?with_htmldocs: %global with_htmldocs 0} %{!?with_monitor: %global with_monitor 1} # crash is not available -%ifarch ppc ppc64 %{sparc} aarch64 ppc64le %{mips} +%ifarch ppc ppc64 %{sparc} %{mips} %{!?with_crash: %global with_crash 0} %else %{!?with_crash: %global with_crash 1} @@ -39,9 +39,12 @@ %{!?with_python3_probes: %global with_python3_probes (0%{?fedora} >= 23 || 0%{?rhel} > 7)} %{!?with_httpd: %global with_httpd 0} +# Virt is supported on these arches, even on el7, but it's not in core EL7 +%if 0%{?rhel} <= 7 %ifarch ppc64le aarch64 %global with_virthost 0 %endif +%endif %if 0%{?fedora} >= 18 || 0%{?rhel} >= 6 %define initdir %{_initddir} @@ -83,8 +86,8 @@ %define __brp_mangle_shebangs_exclude_from .stp$ Name: systemtap -Version: 4.0 -Release: 7%{?release_override}%{?dist} +Version: 4.1 +Release: 6%{?release_override}%{?dist} # for version, see also configure.ac @@ -116,48 +119,14 @@ Release: 7%{?release_override}%{?dist} # intermediary stap-server for --use-server: systemtap-server (-devel unused) Summary: Programmable system-wide instrumentation system -Group: Development/System License: GPLv2+ URL: http://sourceware.org/systemtap/ Source: ftp://sourceware.org/pub/systemtap/releases/systemtap-%{version}.tar.gz -# backported patch series for RHBZ1643997, will go away after 4.1 release: -Patch2: rhbz1643997.0001-testsuite-systemtap.bpf-diagnose-a-bug-in-print_form.patch -Patch3: rhbz1643997.0002-stapbpf-assembler-WIP-1-basic-parser-and-control-flo.patch -Patch4: rhbz1643997.0003-stapbpf-assembler-WIP-2-testcases-no-driver-so-far.patch -Patch5: rhbz1643997.0004-stapbpf-assembler-WIP-3-additional-assembly-test-cas.patch -Patch6: rhbz1643997.0005-stapbpf-assembler-WIP-4-alloc-and-helper-call-operat.patch -Patch7: rhbz1643997.0006-stapbpf-assembler-WIP-5-basic-kernel_string-implemen.patch -Patch8: rhbz1643997.0007-stapbpf-assembler-WIP-6-other-call-functions-s-print.patch -Patch9: rhbz1643997.0008-stapbpf-assembler-WIP-7-fixed-kernel_string-tapset-a.patch -Patch10: rhbz1643997.0009-stapbpf-assembler-WIP-8-bpf-asm.exp-driver-and-more-.patch -Patch11: rhbz1643997.0010-bpf-translate.cxx-plug-an-exception-gap-in-is_numeri.patch -Patch12: rhbz1643997.0011-session.cxx-enable-caching-for-bpf-backend.patch -Patch13: rhbz1643997.0012-Adjust-the-BPF-translate-error-report-formatting-to-.patch -Patch14: rhbz1643997.0013-bpf-translate.cxx-fix-segfault-with-malformed-regist.patch -Patch15: rhbz1643997.0014-bpf-asm.exp-bugfix-bad_output-does-occur.patch -Patch16: rhbz1643997.0015-tapset-bpf-conversions.stp-bugfix-helper-name-in-ker.patch -Patch17: rhbz1643997.0016-tapset-bpf-context.stp-add-execname-triage-other-fun.patch -Patch18: rhbz1643997.0017-PR23849-temporarily-disable-stapbpf-script-caching.patch -Patch19: rhbz1643997.0018-tapset-bpf-task.stp-rudiment-of-task-tapset.patch -Patch20: rhbz1643997.0019-PR23829-fallback-defines-__BPF_FUNC_MAPPER-and-BPF_J.patch -Patch21: rhbz1643997.0020-PR23860-partial-fix-fix-BPF_NEG-opcode-generation.patch -Patch22: rhbz1643997.0021-bpf-behind-the-scenes-useful-DEBUG_CODEGEN-diagnosti.patch -Patch23: rhbz1643997.0022-standardize-ktime_get_ns-across-lkm-bpf-runtimes.patch -Patch24: rhbz1643997.0023-pr23860-verifier-workaround-be-sure-to-delete-all-mo.patch -Patch25: rhbz1643997.0024-PR23860-bugfix-incorrect-comparison-direction-in-str.patch -Patch26: rhbz1643997.0025-PR23860-additional-stack-protection-for-strings.patch -Patch27: rhbz1643997.0026-PR23860-additional-ugly-stack-clobber-protection-for.patch -Patch28: rhbz1643997.0027-PR23860-reduce-stack-pressure-from-format-strings.patch -Patch29: rhbz1643997.0028-testcase-for-PR23875.patch -Patch30: rhbz1643997.0029-PR23860-bpf_interpret-NEG-should-not-fall-through-to.patch -Patch31: rhbz1643997.0030-PR23875-bpf.exp-fail-testcase-on-stack-smashing.patch -Patch32: rhbz1643997.0031-PR23875-another-testcase-that-loops-indefinitely.patch -Patch33: rhbz1643997.0032-PR23875-bpf_unparser-visit_foreach_loop-temporarily-.patch -Patch34: rhbz1656795.patch -Patch35: rhbz1657186.patch -Patch36: rhbz1657857.patch -Patch37: rhbz1657909.patch +Patch10: pr23074.patch +Patch11: rhbz1732173.patch +Patch12: pr23875_bugfix.patch + # Build* BuildRequires: gcc-c++ @@ -259,7 +228,6 @@ the components needed to locally develop and execute systemtap scripts. %package server Summary: Instrumentation System Server -Group: Development/System License: GPLv2+ URL: http://sourceware.org/systemtap/ Requires: systemtap-devel = %{version}-%{release} @@ -269,8 +237,6 @@ Conflicts: systemtap-client < %{version}-%{release} Requires: nss coreutils Requires: zip unzip Requires(pre): shadow-utils -Requires(post): chkconfig -Requires(preun): chkconfig BuildRequires: nss-devel avahi-devel %if %{with_openssl} Requires: openssl @@ -278,6 +244,8 @@ Requires: openssl %if %{with_systemd} Requires: systemd %else +Requires(post): chkconfig +Requires(preun): chkconfig Requires(preun): initscripts Requires(postun): initscripts %endif @@ -290,13 +258,12 @@ compiles systemtap scripts to kernel objects on their demand. %package devel Summary: Programmable system-wide instrumentation system - development headers, tools -Group: Development/System License: GPLv2+ URL: http://sourceware.org/systemtap/ %if 0%{?rhel} >= 8 || 0%{?fedora} >= 20 -Recommends: kernel-debug-devel -Recommends: kernel-devel +Recommends: (kernel-debug-devel if kernel-debug) +Recommends: (kernel-devel if kernel) %else Requires: kernel-devel-uname-r %endif @@ -318,7 +285,6 @@ a copy of the standard tapset library and the runtime library C files. %package runtime Summary: Programmable system-wide instrumentation system - runtime -Group: Development/System License: GPLv2+ URL: http://sourceware.org/systemtap/ Requires(pre): shadow-utils @@ -334,7 +300,6 @@ using a local or remote systemtap-devel installation. %package client Summary: Programmable system-wide instrumentation system - client -Group: Development/System License: GPLv2+ URL: http://sourceware.org/systemtap/ Requires: zip unzip @@ -358,15 +323,14 @@ documentation, and a copy of the tapset library for reference. %package initscript Summary: Systemtap Initscripts -Group: Development/System License: GPLv2+ URL: http://sourceware.org/systemtap/ Requires: systemtap = %{version}-%{release} -Requires(post): chkconfig -Requires(preun): chkconfig %if %{with_systemd} Requires: systemd %else +Requires(post): chkconfig +Requires(preun): chkconfig Requires(preun): initscripts Requires(postun): initscripts %endif @@ -379,7 +343,6 @@ boot-time probing if supported. %package sdt-devel Summary: Static probe support tools -Group: Development/System License: GPLv2+ and Public Domain URL: http://sourceware.org/systemtap/ %if %{with_pyparsing} @@ -403,7 +366,6 @@ with the optional dtrace-compatibility preprocessor to process related %package testsuite Summary: Instrumentation System Testsuite -Group: Development/System License: GPLv2+ URL: http://sourceware.org/systemtap/ Requires: systemtap = %{version}-%{release} @@ -461,12 +423,12 @@ systemtap on the current system. %if %{with_java} %package runtime-java Summary: Systemtap Java Runtime Support -Group: Development/System License: GPLv2+ URL: http://sourceware.org/systemtap/ Requires: systemtap-runtime = %{version}-%{release} Requires: byteman > 2.0 Requires: iproute +Requires: java-devel %description runtime-java This package includes support files needed to run systemtap scripts @@ -476,7 +438,6 @@ that probe Java processes running on the OpenJDK runtimes using Byteman. %if %{with_python2_probes} %package runtime-python2 Summary: Systemtap Python 2 Runtime Support -Group: Development/System License: GPLv2+ URL: http://sourceware.org/systemtap/ Requires: systemtap-runtime = %{version}-%{release} @@ -489,7 +450,6 @@ that probe python 2 processes. %if %{with_python3_probes} %package runtime-python3 Summary: Systemtap Python 3 Runtime Support -Group: Development/System License: GPLv2+ URL: http://sourceware.org/systemtap/ Requires: systemtap-runtime = %{version}-%{release} @@ -507,7 +467,6 @@ that probe python 3 processes. %if %{with_python3} %package exporter Summary: Systemtap-prometheus interoperation mechanism -Group: Development/System License: GPLv2+ URL: http://sourceware.org/systemtap/ Requires: systemtap-runtime = %{version}-%{release} @@ -521,7 +480,6 @@ to remote requesters on demand. %if %{with_virthost} %package runtime-virthost Summary: Systemtap Cross-VM Instrumentation - host -Group: Development/System License: GPLv2+ URL: http://sourceware.org/systemtap/ Requires: libvirt >= 1.0.2 @@ -536,7 +494,6 @@ connection. %if %{with_virtguest} %package runtime-virtguest Summary: Systemtap Cross-VM Instrumentation - guest -Group: Development/System License: GPLv2+ URL: http://sourceware.org/systemtap/ Requires: systemtap-runtime = %{version}-%{release} @@ -558,7 +515,6 @@ systemtap-runtime-virthost machine to execute systemtap scripts. # ------------------------------------------------------------------------ %prep - %setup -q %{?setup_elfutils} %if %{with_bundled_elfutils} @@ -571,43 +527,9 @@ find . \( -name configure -o -name config.h.in \) -print | xargs touch cd .. %endif -# backported patch series for RHBZ1643997, will go away after 4.1 release: -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 %patch10 -p1 %patch11 -p1 %patch12 -p1 -%patch13 -p1 -%patch14 -p1 -%patch15 -p1 -%patch16 -p1 -%patch17 -p1 -%patch18 -p1 -%patch19 -p1 -%patch20 -p1 -%patch21 -p1 -%patch22 -p1 -%patch23 -p1 -%patch24 -p1 -%patch25 -p1 -%patch26 -p1 -%patch27 -p1 -%patch28 -p1 -%patch29 -p1 -%patch30 -p1 -%patch31 -p1 -%patch32 -p1 -%patch33 -p1 -%patch34 -p1 -%patch35 -p1 -%patch36 -p1 -%patch37 -p1 %build @@ -729,7 +651,6 @@ make %{?_smp_mflags} %endif %install -rm -rf ${RPM_BUILD_ROOT} make DESTDIR=$RPM_BUILD_ROOT install %find_lang %{name} for dir in $(ls -1d $RPM_BUILD_ROOT%{_mandir}/{??,??_??}) ; do @@ -856,13 +777,13 @@ done %endif %pre runtime -getent group stapusr >/dev/null || groupadd -g 156 -r stapusr 2>/dev/null || groupadd -r stapusr -getent group stapsys >/dev/null || groupadd -g 157 -r stapsys 2>/dev/null || groupadd -r stapsys -getent group stapdev >/dev/null || groupadd -g 158 -r stapdev 2>/dev/null || groupadd -r stapdev +getent group stapusr >/dev/null || groupadd -f -g 156 -r stapusr +getent group stapsys >/dev/null || groupadd -f -g 157 -r stapsys +getent group stapdev >/dev/null || groupadd -f -g 158 -r stapdev exit 0 %pre server -getent group stap-server >/dev/null || groupadd -g 155 -r stap-server 2>/dev/null || groupadd -r stap-server +getent group stap-server >/dev/null || groupadd -f -g 155 -r stap-server getent passwd stap-server >/dev/null || \ useradd -c "Systemtap Compile Server" -u 155 -g stap-server -d %{_localstatedir}/lib/stap-server -r -s /sbin/nologin stap-server 2>/dev/null || \ useradd -c "Systemtap Compile Server" -g stap-server -d %{_localstatedir}/lib/stap-server -r -s /sbin/nologin stap-server @@ -1116,7 +1037,6 @@ done # The master "systemtap" rpm doesn't include any files. %files server -f systemtap.lang -%defattr(-,root,root) %{_bindir}/stap-server %dir %{_libexecdir}/systemtap %{_libexecdir}/systemtap/stap-serverd @@ -1189,7 +1109,6 @@ done %files runtime -f systemtap.lang -%defattr(-,root,root) %attr(4110,root,stapusr) %{_bindir}/staprun %{_bindir}/stapsh %{_bindir}/stap-merge @@ -1225,7 +1144,6 @@ done %files client -f systemtap.lang -%defattr(-,root,root) %doc README README.unprivileged AUTHORS NEWS %{_datadir}/systemtap/examples %{!?_licensedir:%global license %%doc} @@ -1255,7 +1173,6 @@ done %files initscript -%defattr(-,root,root) %if %{with_systemd} %{_unitdir}/systemtap.service %{_sbindir}/systemtap-service @@ -1277,7 +1194,6 @@ done %files sdt-devel -%defattr(-,root,root) %{_bindir}/dtrace %{_includedir}/sys/sdt.h %{_includedir}/sys/sdt-config.h @@ -1289,7 +1205,6 @@ done %files testsuite -%defattr(-,root,root) %dir %{_datadir}/systemtap %{_datadir}/systemtap/testsuite @@ -1351,6 +1266,24 @@ done # PRERELEASE %changelog +* Tue Aug 06 2019 Frank Ch. Eigler - 4.1-6 +- rhbz1732514: add java-devel prereq to systemtap-runtime-java + +* Wed Jul 31 2019 Serguei Makarov - 4.1-5 +- rhbz1734973: Fix possible stapbpf segfault with foreach string key iteration. + +* Mon Jul 29 2019 Frank Ch. Eigler - 4.1-4 +- rhbz1732173 (arm64 syscall parameters) + +* Tue Jun 04 2019 Stan Cox - 4.1-3 +- Rebuilt for dyninst 10.1.0 + +* Tue May 14 2019 Frank Ch. Eigler - 4.1-2 +- Correct GNU_parameter_ref dwarf feature typo. + +* Tue May 07 2019 Serguei Makarov - 4.1-1 +- Upstream release. + * Mon Dec 17 2018 Frank Ch. Eigler - 4.0-7 - rhbz1657909: vfs tapset fixes for $cred