Commit 59626472 authored by Alastair Robertson's avatar Alastair Robertson

Add support for escape characters in strings

parent 5a73475e
...@@ -110,7 +110,7 @@ Functions: ...@@ -110,7 +110,7 @@ Functions:
- `count()` - count the number of times this function is called - `count()` - count the number of times this function is called
- `delete()` - delete the map element this is assigned to - `delete()` - delete the map element this is assigned to
- `str(char *s)` - returns the string pointed to by `s` - `str(char *s)` - returns the string pointed to by `s`
- `printf(char *fmt, ...)` - write to stdout (support for escape characters is coming) - `printf(char *fmt, ...)` - write to stdout
# Building # Building
......
...@@ -58,36 +58,31 @@ void perf_event_printer(void *cb_cookie, void *data, int size) ...@@ -58,36 +58,31 @@ void perf_event_printer(void *cb_cookie, void *data, int size)
arg_data += arg.size; arg_data += arg.size;
} }
// TODO remove when \n works with the lexer
std::string fmt_newline(fmt);
fmt_newline += "\n";
switch (args.size()) switch (args.size())
{ {
case 0: case 0:
printf(fmt_newline.c_str()); printf(fmt);
break; break;
case 1: case 1:
printf(fmt_newline.c_str(), arg_values.at(0)); printf(fmt, arg_values.at(0));
break; break;
case 2: case 2:
printf(fmt_newline.c_str(), arg_values.at(0), arg_values.at(1)); printf(fmt, arg_values.at(0), arg_values.at(1));
break; break;
case 3: case 3:
printf(fmt_newline.c_str(), arg_values.at(0), arg_values.at(1), printf(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2));
arg_values.at(2));
break; break;
case 4: case 4:
printf(fmt_newline.c_str(), arg_values.at(0), arg_values.at(1), printf(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2),
arg_values.at(2), arg_values.at(3)); arg_values.at(3));
break; break;
case 5: case 5:
printf(fmt_newline.c_str(), arg_values.at(0), arg_values.at(1), printf(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2),
arg_values.at(2), arg_values.at(3), arg_values.at(4)); arg_values.at(3), arg_values.at(4));
break; break;
case 6: case 6:
printf(fmt_newline.c_str(), arg_values.at(0), arg_values.at(1), printf(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2),
arg_values.at(2), arg_values.at(3), arg_values.at(4), arg_values.at(5)); arg_values.at(3), arg_values.at(4), arg_values.at(5));
break; break;
default: default:
abort(); abort();
......
...@@ -24,6 +24,7 @@ public: ...@@ -24,6 +24,7 @@ public:
void error(const location &l, const std::string &m) void error(const location &l, const std::string &m)
{ {
std::cerr << l << ": " << m << std::endl; std::cerr << l << ": " << m << std::endl;
exit(-1);
} }
void error(const std::string &m) void error(const std::string &m)
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#define yywrap(x) 1 #define yywrap(x) 1
static bpftrace::location loc; static bpftrace::location loc;
static std::string string_buffer;
#define YY_USER_ACTION loc.columns(yyleng); #define YY_USER_ACTION loc.columns(yyleng);
#define yyterminate() return bpftrace::Parser::make_END(loc) #define yyterminate() return bpftrace::Parser::make_END(loc)
...@@ -24,7 +25,7 @@ hspace [ \t] ...@@ -24,7 +25,7 @@ hspace [ \t]
vspace [\n\r] vspace [\n\r]
space {hspace}|{vspace} space {hspace}|{vspace}
path :(\\.|[_\-\./a-zA-Z0-9])*: path :(\\.|[_\-\./a-zA-Z0-9])*:
string \"(\\.|[^\\"])*\" %x STR
%% %%
...@@ -38,7 +39,6 @@ string \"(\\.|[^\\"])*\" ...@@ -38,7 +39,6 @@ string \"(\\.|[^\\"])*\"
{ident} { return Parser::make_IDENT(yytext, loc); } {ident} { return Parser::make_IDENT(yytext, loc); }
{path} { return Parser::make_PATH(yytext, loc); } {path} { return Parser::make_PATH(yytext, loc); }
{string} { return Parser::make_STRING(yytext, loc); }
{map} { return Parser::make_MAP(yytext, loc); } {map} { return Parser::make_MAP(yytext, loc); }
{var} { return Parser::make_VAR(yytext, loc); } {var} { return Parser::make_VAR(yytext, loc); }
{int} { return Parser::make_INT(strtoul(yytext, NULL, 0), loc); } {int} { return Parser::make_INT(strtoul(yytext, NULL, 0), loc); }
...@@ -72,6 +72,21 @@ string \"(\\.|[^\\"])*\" ...@@ -72,6 +72,21 @@ string \"(\\.|[^\\"])*\"
"!" { return Parser::make_LNOT(loc); } "!" { return Parser::make_LNOT(loc); }
"~" { return Parser::make_BNOT(loc); } "~" { return Parser::make_BNOT(loc); }
. { driver.error(loc, std::string("invalid character: ")+std::string(yytext)); exit(1); } \" { BEGIN(STR); string_buffer.clear(); }
<STR>\" { BEGIN(INITIAL); return Parser::make_STRING(string_buffer, loc); }
<STR>[^\\\n\"]+ { string_buffer += std::string(yytext); }
<STR>\\n { string_buffer += std::string("\n"); }
<STR>\\t { string_buffer += std::string("\t"); }
<STR>\\\" { string_buffer += std::string("\""); }
<STR>\\\\ { string_buffer += std::string("\\"); }
<STR>\n { driver.error(loc, std::string("unterminated string")); }
<STR><<EOF>> { driver.error(loc, std::string("unterminated string")); }
<STR>\\. { driver.error(loc, std::string("invalid escape character '") +
std::string(yytext) + std::string("'")); }
<STR>. { driver.error(loc, std::string("invalid character '") +
std::string(yytext) + std::string("'")); }
. { driver.error(loc, std::string("invalid character '") +
std::string(yytext) + std::string("'")); }
%% %%
...@@ -85,8 +85,6 @@ void yyerror(bpftrace::Driver &driver, const char *s); ...@@ -85,8 +85,6 @@ void yyerror(bpftrace::Driver &driver, const char *s);
%type <ast::Variable *> var %type <ast::Variable *> var
%type <ast::ExpressionList *> vargs %type <ast::ExpressionList *> vargs
%printer { yyoutput << %%; } <*>;
%right ASSIGN %right ASSIGN
%left LOR %left LOR
%left LAND %left LAND
...@@ -130,7 +128,7 @@ stmt : expr { $$ = new ast::ExprStatement($1); } ...@@ -130,7 +128,7 @@ stmt : expr { $$ = new ast::ExprStatement($1); }
; ;
expr : INT { $$ = new ast::Integer($1); } expr : INT { $$ = new ast::Integer($1); }
| STRING { $$ = new ast::String($1.substr(1, $1.size()-2)); } | STRING { $$ = new ast::String($1); }
| IDENT { $$ = new ast::Builtin($1); } | IDENT { $$ = new ast::Builtin($1); }
| map { $$ = $1; } | map { $$ = $1; }
| var { $$ = $1; } | var { $$ = $1; }
......
#include <regex>
#include "printer.h" #include "printer.h"
#include "ast.h" #include "ast.h"
...@@ -13,7 +15,14 @@ void Printer::visit(Integer &integer) ...@@ -13,7 +15,14 @@ void Printer::visit(Integer &integer)
void Printer::visit(String &string) void Printer::visit(String &string)
{ {
std::string indent(depth_, ' '); std::string indent(depth_, ' ');
out_ << indent << "string: " << string.str << std::endl;
std::string str = string.str;
str = std::regex_replace(str, std::regex("\\\\"), "\\\\");
str = std::regex_replace(str, std::regex("\n"), "\\n");
str = std::regex_replace(str, std::regex("\t"), "\\t");
str = std::regex_replace(str, std::regex("\""), "\\\"");
out_ << indent << "string: " << str << std::endl;
} }
void Printer::visit(Builtin &builtin) void Printer::visit(Builtin &builtin)
......
...@@ -40,6 +40,7 @@ std::string verify_format_string(const std::string &fmt, std::vector<SizedType> ...@@ -40,6 +40,7 @@ std::string verify_format_string(const std::string &fmt, std::vector<SizedType>
case 'u': case 'u':
case 'x': case 'x':
case 'X': case 'X':
case 'p':
token_type = Type::integer; token_type = Type::integer;
break; break;
case 's': case 's':
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include "printer.h" #include "printer.h"
namespace bpftrace { namespace bpftrace {
namespace test {
namespace parser {
using Printer = ast::Printer; using Printer = ast::Printer;
...@@ -202,4 +204,14 @@ TEST(Parser, uprobe) ...@@ -202,4 +204,14 @@ TEST(Parser, uprobe)
" int: 1\n"); " int: 1\n");
} }
TEST(Parser, escape_chars)
{
test("kprobe:sys_open { \"newline\\nand tab\\tbackslash\\\\quote\\\"here\" }",
"Program\n"
" kprobe:sys_open\n"
" string: newline\\nand tab\\tbackslash\\\\quote\\\"here\n");
}
} // namespace parser
} // namespace test
} // namespace bpftrace } // namespace bpftrace
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include "semantic_analyser.h" #include "semantic_analyser.h"
namespace bpftrace { namespace bpftrace {
namespace test {
namespace semantic_analyser {
class MockBPFtrace : public BPFtrace { class MockBPFtrace : public BPFtrace {
public: public:
...@@ -185,4 +187,6 @@ TEST(semantic_analyser, printf_format_multi) ...@@ -185,4 +187,6 @@ TEST(semantic_analyser, printf_format_multi)
test("kprobe:f { printf(\"%d %s %d\", 1, 2, \"mystr\") }", 10); test("kprobe:f { printf(\"%d %s %d\", 1, 2, \"mystr\") }", 10);
} }
} // namespace semantic_analyser
} // namespace test
} // namespace bpftrace } // namespace bpftrace
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment