Skip to content

Commit 032330a

Browse files
committed
tracing/probes: Cleanup probe argument parser
Cleanup traceprobe_parse_probe_arg_body() to split out the type parser and post-processing part of fetch_insn. This makes no functional change. Link: https://lore.kernel.org/all/170952362603.229804.9942703761682605372.stgit@devnote2/ Signed-off-by: Masami Hiramatsu (Google) <[email protected]> Reviewed-by: Steven Rostedt (Google) <[email protected]>
1 parent 7e37b6b commit 032330a

File tree

1 file changed

+137
-93
lines changed

1 file changed

+137
-93
lines changed

kernel/trace/trace_probe.c

Lines changed: 137 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,67 +1090,45 @@ static int __parse_bitfield_probe_arg(const char *bf,
10901090
return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0;
10911091
}
10921092

1093-
/* String length checking wrapper */
1094-
static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
1095-
struct probe_arg *parg,
1096-
struct traceprobe_parse_context *ctx)
1093+
/* Split type part from @arg and return it. */
1094+
static char *parse_probe_arg_type(char *arg, struct probe_arg *parg,
1095+
struct traceprobe_parse_context *ctx)
10971096
{
1098-
struct fetch_insn *code, *scode, *tmp = NULL;
1099-
char *t, *t2, *t3;
1100-
int ret, len;
1101-
char *arg;
1097+
char *t = NULL, *t2, *t3;
1098+
int offs;
11021099

1103-
arg = kstrdup(argv, GFP_KERNEL);
1104-
if (!arg)
1105-
return -ENOMEM;
1106-
1107-
ret = -EINVAL;
1108-
len = strlen(arg);
1109-
if (len > MAX_ARGSTR_LEN) {
1110-
trace_probe_log_err(ctx->offset, ARG_TOO_LONG);
1111-
goto out;
1112-
} else if (len == 0) {
1113-
trace_probe_log_err(ctx->offset, NO_ARG_BODY);
1114-
goto out;
1115-
}
1116-
1117-
ret = -ENOMEM;
1118-
parg->comm = kstrdup(arg, GFP_KERNEL);
1119-
if (!parg->comm)
1120-
goto out;
1121-
1122-
ret = -EINVAL;
11231100
t = strchr(arg, ':');
11241101
if (t) {
1125-
*t = '\0';
1126-
t2 = strchr(++t, '[');
1102+
*t++ = '\0';
1103+
t2 = strchr(t, '[');
11271104
if (t2) {
11281105
*t2++ = '\0';
11291106
t3 = strchr(t2, ']');
11301107
if (!t3) {
1131-
int offs = t2 + strlen(t2) - arg;
1108+
offs = t2 + strlen(t2) - arg;
11321109

11331110
trace_probe_log_err(ctx->offset + offs,
11341111
ARRAY_NO_CLOSE);
1135-
goto out;
1112+
return ERR_PTR(-EINVAL);
11361113
} else if (t3[1] != '\0') {
11371114
trace_probe_log_err(ctx->offset + t3 + 1 - arg,
11381115
BAD_ARRAY_SUFFIX);
1139-
goto out;
1116+
return ERR_PTR(-EINVAL);
11401117
}
11411118
*t3 = '\0';
11421119
if (kstrtouint(t2, 0, &parg->count) || !parg->count) {
11431120
trace_probe_log_err(ctx->offset + t2 - arg,
11441121
BAD_ARRAY_NUM);
1145-
goto out;
1122+
return ERR_PTR(-EINVAL);
11461123
}
11471124
if (parg->count > MAX_ARRAY_LEN) {
11481125
trace_probe_log_err(ctx->offset + t2 - arg,
11491126
ARRAY_TOO_BIG);
1150-
goto out;
1127+
return ERR_PTR(-EINVAL);
11511128
}
11521129
}
11531130
}
1131+
offs = t ? t - arg : 0;
11541132

11551133
/*
11561134
* Since $comm and immediate string can not be dereferenced,
@@ -1161,74 +1139,52 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
11611139
strncmp(arg, "\\\"", 2) == 0)) {
11621140
/* The type of $comm must be "string", and not an array type. */
11631141
if (parg->count || (t && strcmp(t, "string"))) {
1164-
trace_probe_log_err(ctx->offset + (t ? (t - arg) : 0),
1165-
NEED_STRING_TYPE);
1166-
goto out;
1142+
trace_probe_log_err(ctx->offset + offs, NEED_STRING_TYPE);
1143+
return ERR_PTR(-EINVAL);
11671144
}
11681145
parg->type = find_fetch_type("string", ctx->flags);
11691146
} else
11701147
parg->type = find_fetch_type(t, ctx->flags);
1148+
11711149
if (!parg->type) {
1172-
trace_probe_log_err(ctx->offset + (t ? (t - arg) : 0), BAD_TYPE);
1173-
goto out;
1150+
trace_probe_log_err(ctx->offset + offs, BAD_TYPE);
1151+
return ERR_PTR(-EINVAL);
11741152
}
11751153

1176-
code = tmp = kcalloc(FETCH_INSN_MAX, sizeof(*code), GFP_KERNEL);
1177-
if (!code)
1178-
goto out;
1179-
code[FETCH_INSN_MAX - 1].op = FETCH_OP_END;
1180-
1181-
ctx->last_type = NULL;
1182-
ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1],
1183-
ctx);
1184-
if (ret)
1185-
goto fail;
1186-
1187-
/* Update storing type if BTF is available */
1188-
if (IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS) &&
1189-
ctx->last_type) {
1190-
if (!t) {
1191-
parg->type = find_fetch_type_from_btf_type(ctx);
1192-
} else if (strstr(t, "string")) {
1193-
ret = check_prepare_btf_string_fetch(t, &code, ctx);
1194-
if (ret)
1195-
goto fail;
1196-
}
1197-
}
1198-
parg->offset = *size;
1199-
*size += parg->type->size * (parg->count ?: 1);
1154+
return t;
1155+
}
12001156

1201-
if (parg->count) {
1202-
len = strlen(parg->type->fmttype) + 6;
1203-
parg->fmt = kmalloc(len, GFP_KERNEL);
1204-
if (!parg->fmt) {
1205-
ret = -ENOMEM;
1206-
goto out;
1207-
}
1208-
snprintf(parg->fmt, len, "%s[%d]", parg->type->fmttype,
1209-
parg->count);
1210-
}
1157+
/* After parsing, adjust the fetch_insn according to the probe_arg */
1158+
static int finalize_fetch_insn(struct fetch_insn *code,
1159+
struct probe_arg *parg,
1160+
char *type,
1161+
int type_offset,
1162+
struct traceprobe_parse_context *ctx)
1163+
{
1164+
struct fetch_insn *scode;
1165+
int ret;
12111166

1212-
ret = -EINVAL;
12131167
/* Store operation */
12141168
if (parg->type->is_string) {
1169+
/* Check bad combination of the type and the last fetch_insn. */
12151170
if (!strcmp(parg->type->name, "symstr")) {
12161171
if (code->op != FETCH_OP_REG && code->op != FETCH_OP_STACK &&
12171172
code->op != FETCH_OP_RETVAL && code->op != FETCH_OP_ARG &&
12181173
code->op != FETCH_OP_DEREF && code->op != FETCH_OP_TP_ARG) {
1219-
trace_probe_log_err(ctx->offset + (t ? (t - arg) : 0),
1174+
trace_probe_log_err(ctx->offset + type_offset,
12201175
BAD_SYMSTRING);
1221-
goto fail;
1176+
return -EINVAL;
12221177
}
12231178
} else {
12241179
if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF &&
12251180
code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM &&
12261181
code->op != FETCH_OP_DATA && code->op != FETCH_OP_TP_ARG) {
1227-
trace_probe_log_err(ctx->offset + (t ? (t - arg) : 0),
1182+
trace_probe_log_err(ctx->offset + type_offset,
12281183
BAD_STRING);
1229-
goto fail;
1184+
return -EINVAL;
12301185
}
12311186
}
1187+
12321188
if (!strcmp(parg->type->name, "symstr") ||
12331189
(code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM ||
12341190
code->op == FETCH_OP_DATA) || code->op == FETCH_OP_TP_ARG ||
@@ -1244,9 +1200,10 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
12441200
code++;
12451201
if (code->op != FETCH_OP_NOP) {
12461202
trace_probe_log_err(ctx->offset, TOO_MANY_OPS);
1247-
goto fail;
1203+
return -EINVAL;
12481204
}
12491205
}
1206+
12501207
/* If op == DEREF, replace it with STRING */
12511208
if (!strcmp(parg->type->name, "ustring") ||
12521209
code->op == FETCH_OP_UDEREF)
@@ -1267,47 +1224,134 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
12671224
code++;
12681225
if (code->op != FETCH_OP_NOP) {
12691226
trace_probe_log_err(ctx->offset, TOO_MANY_OPS);
1270-
goto fail;
1227+
return -E2BIG;
12711228
}
12721229
code->op = FETCH_OP_ST_RAW;
12731230
code->size = parg->type->size;
12741231
}
1232+
1233+
/* Save storing fetch_insn. */
12751234
scode = code;
1235+
12761236
/* Modify operation */
1277-
if (t != NULL) {
1278-
ret = __parse_bitfield_probe_arg(t, parg->type, &code);
1237+
if (type != NULL) {
1238+
/* Bitfield needs a special fetch_insn. */
1239+
ret = __parse_bitfield_probe_arg(type, parg->type, &code);
12791240
if (ret) {
1280-
trace_probe_log_err(ctx->offset + t - arg, BAD_BITFIELD);
1281-
goto fail;
1241+
trace_probe_log_err(ctx->offset + type_offset, BAD_BITFIELD);
1242+
return ret;
12821243
}
12831244
} else if (IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS) &&
12841245
ctx->last_type) {
1246+
/* If user not specified the type, try parsing BTF bitfield. */
12851247
ret = parse_btf_bitfield(&code, ctx);
12861248
if (ret)
1287-
goto fail;
1249+
return ret;
12881250
}
1289-
ret = -EINVAL;
1251+
12901252
/* Loop(Array) operation */
12911253
if (parg->count) {
12921254
if (scode->op != FETCH_OP_ST_MEM &&
12931255
scode->op != FETCH_OP_ST_STRING &&
12941256
scode->op != FETCH_OP_ST_USTRING) {
1295-
trace_probe_log_err(ctx->offset + (t ? (t - arg) : 0),
1296-
BAD_STRING);
1297-
goto fail;
1257+
trace_probe_log_err(ctx->offset + type_offset, BAD_STRING);
1258+
return -EINVAL;
12981259
}
12991260
code++;
13001261
if (code->op != FETCH_OP_NOP) {
13011262
trace_probe_log_err(ctx->offset, TOO_MANY_OPS);
1302-
goto fail;
1263+
return -E2BIG;
13031264
}
13041265
code->op = FETCH_OP_LP_ARRAY;
13051266
code->param = parg->count;
13061267
}
1268+
1269+
/* Finalize the fetch_insn array. */
13071270
code++;
13081271
code->op = FETCH_OP_END;
13091272

1310-
ret = 0;
1273+
return 0;
1274+
}
1275+
1276+
/* String length checking wrapper */
1277+
static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
1278+
struct probe_arg *parg,
1279+
struct traceprobe_parse_context *ctx)
1280+
{
1281+
struct fetch_insn *code, *tmp = NULL;
1282+
char *type, *arg;
1283+
int ret, len;
1284+
1285+
len = strlen(argv);
1286+
if (len > MAX_ARGSTR_LEN) {
1287+
trace_probe_log_err(ctx->offset, ARG_TOO_LONG);
1288+
return -E2BIG;
1289+
} else if (len == 0) {
1290+
trace_probe_log_err(ctx->offset, NO_ARG_BODY);
1291+
return -EINVAL;
1292+
}
1293+
1294+
arg = kstrdup(argv, GFP_KERNEL);
1295+
if (!arg)
1296+
return -ENOMEM;
1297+
1298+
parg->comm = kstrdup(arg, GFP_KERNEL);
1299+
if (!parg->comm) {
1300+
ret = -ENOMEM;
1301+
goto out;
1302+
}
1303+
1304+
type = parse_probe_arg_type(arg, parg, ctx);
1305+
if (IS_ERR(type)) {
1306+
ret = PTR_ERR(type);
1307+
goto out;
1308+
}
1309+
1310+
code = tmp = kcalloc(FETCH_INSN_MAX, sizeof(*code), GFP_KERNEL);
1311+
if (!code) {
1312+
ret = -ENOMEM;
1313+
goto out;
1314+
}
1315+
code[FETCH_INSN_MAX - 1].op = FETCH_OP_END;
1316+
1317+
ctx->last_type = NULL;
1318+
ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1],
1319+
ctx);
1320+
if (ret < 0)
1321+
goto fail;
1322+
1323+
/* Update storing type if BTF is available */
1324+
if (IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS) &&
1325+
ctx->last_type) {
1326+
if (!type) {
1327+
parg->type = find_fetch_type_from_btf_type(ctx);
1328+
} else if (strstr(type, "string")) {
1329+
ret = check_prepare_btf_string_fetch(type, &code, ctx);
1330+
if (ret)
1331+
goto fail;
1332+
}
1333+
}
1334+
parg->offset = *size;
1335+
*size += parg->type->size * (parg->count ?: 1);
1336+
1337+
if (parg->count) {
1338+
len = strlen(parg->type->fmttype) + 6;
1339+
parg->fmt = kmalloc(len, GFP_KERNEL);
1340+
if (!parg->fmt) {
1341+
ret = -ENOMEM;
1342+
goto out;
1343+
}
1344+
snprintf(parg->fmt, len, "%s[%d]", parg->type->fmttype,
1345+
parg->count);
1346+
}
1347+
1348+
ret = finalize_fetch_insn(code, parg, type, type ? type - arg : 0, ctx);
1349+
if (ret < 0)
1350+
goto fail;
1351+
1352+
for (; code < tmp + FETCH_INSN_MAX; code++)
1353+
if (code->op == FETCH_OP_END)
1354+
break;
13111355
/* Shrink down the code buffer */
13121356
parg->code = kcalloc(code - tmp + 1, sizeof(*code), GFP_KERNEL);
13131357
if (!parg->code)
@@ -1316,7 +1360,7 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
13161360
memcpy(parg->code, tmp, sizeof(*code) * (code - tmp + 1));
13171361

13181362
fail:
1319-
if (ret) {
1363+
if (ret < 0) {
13201364
for (code = tmp; code < tmp + FETCH_INSN_MAX; code++)
13211365
if (code->op == FETCH_NOP_SYMBOL ||
13221366
code->op == FETCH_OP_DATA)

0 commit comments

Comments
 (0)