[RFC 04/12] perf event action: Add parsing const string expr support

Yang Jihong
2024-11-28T13:36:36Z

Support parsing of constant string expression.

Signed-off-by: Yang Jihong <yangjihong@bytedance.com>
---
tools/perf/util/parse-action.c | 39 ++++++++++++
tools/perf/util/parse-action.h | 1 +
tools/perf/util/parse-action.l | 108 +++++++++++++++++++++++++++++++++
tools/perf/util/parse-action.y | 10 ++-
4 files changed, 157 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/parse-action.c b/tools/perf/util/parse-action.c
index 3b10cf9f99b3..7e5ca889d5b9 100644
--- a/tools/perf/util/parse-action.c
+++ b/tools/perf/util/parse-action.c
@@ -8,6 +8,7 @@
* Supported expressions:
* - constant:
* - integer
+ * - string
*/

#include "util/debug.h"
@@ -169,8 +170,46 @@ static struct evtact_expr_ops expr_const_int_ops = {
.eval = expr_const_int_eval,
};

+static int expr_const_str_new(struct evtact_expr *expr,
+ void *data, int size __maybe_unused)
+{
+ if (data == NULL) {
+ pr_err("exper const string is NULL\n");
+ return -EINVAL;
+ }
+
+ expr->priv = data;
+ INIT_LIST_HEAD(&expr->opnds);
+ return 0;
+}
+
+static void expr_const_str_free(struct evtact_expr *expr)
+{
+ zfree(&expr->priv);
+}
+
+static int expr_const_str_eval(struct evtact_expr *expr,
+ void *in __maybe_unused, int in_size __maybe_unused,
+ void **out, int *out_size)
+{
+ if (out != NULL)
+ *out = expr->priv;
+
+ if (out_size != NULL)
+ *out_size = strlen(expr->priv);
+
+ return 0;
+}
+
+static struct evtact_expr_ops expr_const_str_ops = {
+ .new = expr_const_str_new,
+ .free = expr_const_str_free,
+ .eval = expr_const_str_eval,
+};
+
static struct evtact_expr_ops *expr_const_ops_list[EVTACT_EXPR_CONST_TYPE_MAX] = {
[EVTACT_EXPR_CONST_TYPE_INT] = &expr_const_int_ops,
+ [EVTACT_EXPR_CONST_TYPE_STR] = &expr_const_str_ops,
};

static int expr_const_set_ops(struct evtact_expr *expr, u32 opcode)
diff --git a/tools/perf/util/parse-action.h b/tools/perf/util/parse-action.h
index ac81278c590e..ec422f8a05a7 100644
--- a/tools/perf/util/parse-action.h
+++ b/tools/perf/util/parse-action.h
@@ -15,6 +15,7 @@ enum evtact_expr_type {

enum evtact_expr_const_type {
EVTACT_EXPR_CONST_TYPE_INT,
+ EVTACT_EXPR_CONST_TYPE_STR,
EVTACT_EXPR_CONST_TYPE_MAX,
};

diff --git a/tools/perf/util/parse-action.l b/tools/perf/util/parse-action.l
index 9237399a11ac..f76240276b61 100644
--- a/tools/perf/util/parse-action.l
+++ b/tools/perf/util/parse-action.l
@@ -28,6 +28,54 @@ static int value(int base)
return NUMBER;
}

+static char *str_buf;
+static unsigned int str_buf_size = 64;
+static int str_begin(void)
+{
+ if (str_buf == NULL) {
+ str_buf = malloc(str_buf_size);
+ if (str_buf == NULL) {
+ pr_err("parse_action malloc string buffer failed\n");
+ return ERROR;
+ }
+ }
+
+ str_buf[0] = '\0';
+ return 0;
+}
+
+static int str_write(const char *s)
+{
+ char *new_buf;
+
+ if (strlen(str_buf) + strlen(s) >= str_buf_size) {
+ str_buf_size = strlen(str_buf) + strlen(s) + 1;
+ new_buf = realloc(str_buf, str_buf_size);
+ if (new_buf == NULL) {
+ free(str_buf);
+ str_buf = NULL;
+ pr_err("parse_action realloc string buffer failed\n");
+ return ERROR;
+ } else {
+ str_buf = new_buf;
+ }
+ }
+
+ strcat(str_buf, s);
+ return 0;
+}
+
+static int str_end(void)
+{
+ parse_action_lval.str = strdup(str_buf);
+ if (parse_action_lval.str == NULL) {
+ pr_err("parse_action strdup string buffer failed\n");
+ return ERROR;
+ }
+
+ return STRING;
+}
+
%}

num_dec [0-9]+
@@ -35,6 +83,8 @@ num_hex 0[xX][0-9a-fA-F]+
space [ \t]
ident [_a-zA-Z][_a-zA-Z0-9]*

+%x STR_BEGIN
+
%%

{num_dec} { return value(10); }
@@ -43,6 +93,64 @@ ident [_a-zA-Z][_a-zA-Z0-9]*

";" { return SEMI; }

+\" {
+ int ret;
+ yy_push_state(STR_BEGIN);
+ ret = str_begin();
+ if (ret) {
+ yy_pop_state();
+ return ret;
+ }
+ }
+<STR_BEGIN>{
+ \" {
+ yy_pop_state();
+ return str_end();
+ }
+ [^\\\n\"]+ {
+ int ret;
+ ret = str_write((const char *)yytext);
+ if (ret) {
+ yy_pop_state();
+ return ret;
+ }
+ }
+ \\n {
+ int ret;
+ ret = str_write("\n");
+ if (ret) {
+ yy_pop_state();
+ return ret;
+ }
+ }
+ \\t {
+ int ret;
+ ret = str_write("\t");
+ if (ret) {
+ yy_pop_state();
+ return ret;
+ }
+ }
+ \\\\ {
+ int ret;
+ ret = str_write("\\");
+ if (ret) {
+ yy_pop_state();
+ return ret;
+ }
+ }
+ \\. {
+ yy_pop_state();
+ pr_err("parse_action invalid escape character: '%s'\n", parse_action_text);
+ return ERROR;
+ }
+ . {
+ yy_pop_state();
+ pr_err("parse_action invalid character: '%s'\n", parse_action_text);
+ return ERROR;
+ }
+}
+
{ident} {
parse_action_lval.str = strdup(parse_action_text);
if (parse_action_lval.str == NULL) {
diff --git a/tools/perf/util/parse-action.y b/tools/perf/util/parse-action.y
index 51e77e54f157..4922b2d94aee 100644
--- a/tools/perf/util/parse-action.y
+++ b/tools/perf/util/parse-action.y
@@ -37,12 +37,13 @@ static void parse_action_error(struct list_head *expr __maybe_unused,
unsigned long long num;
}

-%token IDENT ERROR NUMBER
+%token IDENT ERROR NUMBER STRING
%token SEMI
%type <expr> action_term expr_term
%destructor { parse_action_expr__free($$); } <expr>
%type <str> IDENT
%type <num> NUMBER
+%type <str> STRING

%%

@@ -76,6 +77,13 @@ NUMBER
YYERROR;
}
|
+STRING
+{
+ $$ = parse_action_expr__new(expr_id(CONST, STR), NULL, (void *)$1, strlen($1));
+ if ($$ == NULL)
+ YYERROR;
+}
+|
IDENT
{
$$ = NULL;
--
2.25.1