From: Mykyta Yatsenko <yatsenko@xxxxxxxx> Refactor var preset parsing in veristat to simplify implementation. Prepare parsed variable beforehand so that parsing logic is separated from functionality of calculating offsets and searching fields. Introduce variant struct, storing either int or enum (string value), will be reused in the next patch, extract parsing variant into a separate function. Signed-off-by: Mykyta Yatsenko <yatsenko@xxxxxxxx> --- tools/testing/selftests/bpf/veristat.c | 160 ++++++++++++++++--------- 1 file changed, 103 insertions(+), 57 deletions(-) diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c index b2bb20b00952..8291de199aab 100644 --- a/tools/testing/selftests/bpf/veristat.c +++ b/tools/testing/selftests/bpf/veristat.c @@ -155,13 +155,23 @@ struct filter { bool abs; }; -struct var_preset { - char *name; - enum { INTEGRAL, ENUMERATOR } type; +struct variant { + enum { NONE, INTEGRAL, ENUMERATOR } type; union { long long ivalue; char *svalue; }; +}; + +struct var_preset_atom { + char *name; +}; + +struct var_preset { + struct var_preset_atom *atoms; + int atom_count; + char *full_name; + struct variant value; bool applied; }; @@ -1278,6 +1288,35 @@ static int max_verifier_log_size(void) return log_size; } +static int parse_variant(const char *val, struct variant *variant) +{ + long long value; + char *val_end; + + if (val[0] == '-' || isdigit(val[0])) { + /* must be a number */ + errno = 0; + value = strtoll(val, &val_end, 0); + if (errno == ERANGE) { + errno = 0; + value = strtoull(val, &val_end, 0); + } + if (errno || *val_end != '\0') { + fprintf(stderr, "Failed to parse value '%s'\n", val); + return -EINVAL; + } + variant->ivalue = value; + variant->type = INTEGRAL; + } else { + /* if not a number, consider it enum value */ + variant->svalue = strdup(val); + if (!variant->svalue) + return -ENOMEM; + variant->type = ENUMERATOR; + } + return 0; +} + static int process_prog(const char *filename, struct bpf_object *obj, struct bpf_program *prog) { const char *base_filename = basename(strdupa(filename)); @@ -1363,13 +1402,36 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf return 0; }; +static int parse_var_atoms(const char *full_var, struct var_preset *preset) +{ + char expr[256], *name, *saveptr; + + snprintf(expr, sizeof(expr), "%s", full_var); + preset->atom_count = 0; + while ((name = strtok_r(preset->atom_count ? NULL : expr, ".", &saveptr))) { + struct var_preset_atom *tmp; + int i = preset->atom_count; + + tmp = reallocarray(preset->atoms, i + 1, sizeof(*preset->atoms)); + if (!tmp) + return -ENOMEM; + + preset->atoms = tmp; + preset->atom_count++; + + preset->atoms[i].name = strdup(name); + if (!preset->atoms[i].name) + return -ENOMEM; + } + return 0; +} + static int append_var_preset(struct var_preset **presets, int *cnt, const char *expr) { void *tmp; struct var_preset *cur; - char var[256], val[256], *val_end; - long long value; - int n; + char var[256], val[256]; + int n, err; tmp = realloc(*presets, (*cnt + 1) * sizeof(**presets)); if (!tmp) @@ -1384,32 +1446,18 @@ static int append_var_preset(struct var_preset **presets, int *cnt, const char * return -EINVAL; } - if (val[0] == '-' || isdigit(val[0])) { - /* must be a number */ - errno = 0; - value = strtoll(val, &val_end, 0); - if (errno == ERANGE) { - errno = 0; - value = strtoull(val, &val_end, 0); - } - if (errno || *val_end != '\0') { - fprintf(stderr, "Failed to parse value '%s'\n", val); - return -EINVAL; - } - cur->ivalue = value; - cur->type = INTEGRAL; - } else { - /* if not a number, consider it enum value */ - cur->svalue = strdup(val); - if (!cur->svalue) - return -ENOMEM; - cur->type = ENUMERATOR; - } + err = parse_variant(val, &cur->value); + if (err) + return err; - cur->name = strdup(var); - if (!cur->name) + cur->full_name = strdup(var); + if (!cur->full_name) return -ENOMEM; + err = parse_var_atoms(var, cur); + if (err) + return err; + return 0; } @@ -1489,7 +1537,7 @@ static bool is_preset_supported(const struct btf_type *t) const int btf_find_member(const struct btf *btf, const struct btf_type *parent_type, __u32 parent_offset, - const char *member_name, + struct var_preset_atom *var_atom, int *member_tid, __u32 *member_offset) { @@ -1512,7 +1560,7 @@ const int btf_find_member(const struct btf *btf, if (member->name_off) { const char *name = btf__name_by_offset(btf, member->name_off); - if (strcmp(member_name, name) == 0) { + if (strcmp(var_atom->name, name) == 0) { if (btf_member_bitfield_size(parent_type, i) != 0) { fprintf(stderr, "Bitfield presets are not supported %s\n", name); @@ -1526,7 +1574,7 @@ const int btf_find_member(const struct btf *btf, int err; err = btf_find_member(btf, member_type, parent_offset + member->offset, - member_name, member_tid, member_offset); + var_atom, member_tid, member_offset); if (!err) return 0; } @@ -1536,22 +1584,20 @@ const int btf_find_member(const struct btf *btf, } static int adjust_var_secinfo(struct btf *btf, const struct btf_type *t, - struct btf_var_secinfo *sinfo, const char *var) + struct btf_var_secinfo *sinfo, struct var_preset *preset) { - char expr[256], *saveptr; const struct btf_type *base_type, *member_type; - int err, member_tid; - char *name; + int err, member_tid, i; __u32 member_offset = 0; base_type = btf__type_by_id(btf, btf__resolve_type(btf, t->type)); - snprintf(expr, sizeof(expr), "%s", var); - strtok_r(expr, ".", &saveptr); - while ((name = strtok_r(NULL, ".", &saveptr))) { - err = btf_find_member(btf, base_type, 0, name, &member_tid, &member_offset); + for (i = 1; i < preset->atom_count; ++i) { + err = btf_find_member(btf, base_type, 0, &preset->atoms[i], + &member_tid, &member_offset); if (err) { - fprintf(stderr, "Could not find member %s for variable %s\n", name, var); + fprintf(stderr, "Could not find member %s for variable %s\n", + preset->atoms[i].name, preset->atoms[i - 1].name); return err; } member_type = btf__type_by_id(btf, member_tid); @@ -1569,7 +1615,7 @@ static int set_global_var(struct bpf_object *obj, struct btf *btf, { const struct btf_type *base_type; void *ptr; - long long value = preset->ivalue; + long long value = preset->value.ivalue; size_t size; base_type = btf__type_by_id(btf, btf__resolve_type(btf, sinfo->type)); @@ -1583,17 +1629,18 @@ static int set_global_var(struct bpf_object *obj, struct btf *btf, return -EINVAL; } - if (preset->type == ENUMERATOR) { + if (preset->value.type == ENUMERATOR) { if (btf_is_any_enum(base_type)) { - if (enum_value_from_name(btf, base_type, preset->svalue, &value)) { + if (enum_value_from_name(btf, base_type, preset->value.svalue, &value)) { fprintf(stderr, "Failed to find integer value for enum element %s\n", - preset->svalue); + preset->value.svalue); return -EINVAL; } } else { fprintf(stderr, "Value %s is not supported for type %s\n", - preset->svalue, btf__name_by_offset(btf, base_type->name_off)); + preset->value.svalue, + btf__name_by_offset(btf, base_type->name_off)); return -EINVAL; } } @@ -1660,20 +1707,16 @@ static int set_global_vars(struct bpf_object *obj, struct var_preset *presets, i for (j = 0; j < n; ++j, ++sinfo) { const struct btf_type *var_type = btf__type_by_id(btf, sinfo->type); const char *var_name; - int var_len; if (!btf_is_var(var_type)) continue; var_name = btf__name_by_offset(btf, var_type->name_off); - var_len = strlen(var_name); for (k = 0; k < npresets; ++k) { struct btf_var_secinfo tmp_sinfo; - if (strncmp(var_name, presets[k].name, var_len) != 0 || - (presets[k].name[var_len] != '\0' && - presets[k].name[var_len] != '.')) + if (strcmp(var_name, presets[k].atoms[0].name) != 0) continue; if (presets[k].applied) { @@ -1683,7 +1726,7 @@ static int set_global_vars(struct bpf_object *obj, struct var_preset *presets, i } tmp_sinfo = *sinfo; err = adjust_var_secinfo(btf, var_type, - &tmp_sinfo, presets[k].name); + &tmp_sinfo, presets + k); if (err) return err; @@ -1698,7 +1741,7 @@ static int set_global_vars(struct bpf_object *obj, struct var_preset *presets, i for (i = 0; i < npresets; ++i) { if (!presets[i].applied) { fprintf(stderr, "Global variable preset %s has not been applied\n", - presets[i].name); + presets[i].full_name); } presets[i].applied = false; } @@ -2826,7 +2869,7 @@ static int handle_replay_mode(void) int main(int argc, char **argv) { - int err = 0, i; + int err = 0, i, j; if (argp_parse(&argp, argc, argv, 0, NULL, NULL)) return 1; @@ -2885,9 +2928,12 @@ int main(int argc, char **argv) } free(env.deny_filters); for (i = 0; i < env.npresets; ++i) { - free(env.presets[i].name); - if (env.presets[i].type == ENUMERATOR) - free(env.presets[i].svalue); + free(env.presets[i].full_name); + for (j = 0; j < env.presets[i].atom_count; ++j) + free(env.presets[i].atoms[j].name); + free(env.presets[i].atoms); + if (env.presets[i].value.type == ENUMERATOR) + free(env.presets[i].value.svalue); } free(env.presets); return -err; -- 2.49.0