};
struct field_access {
- char *name;
+ enum { FIELD_NAME, ARRAY_INDEX } type;
+ union {
+ char *name;
+ struct rvalue index;
+ };
};
struct var_preset {
free(buf);
return 0;
-};
+}
+
+static int append_preset_atom(struct var_preset *preset, char *value, bool is_index)
+{
+ struct field_access *tmp;
+ int i = preset->atom_count;
+ int err;
+
+ tmp = reallocarray(preset->atoms, i + 1, sizeof(*preset->atoms));
+ if (!tmp)
+ return -ENOMEM;
+
+ preset->atoms = tmp;
+ preset->atom_count++;
+
+ if (is_index) {
+ preset->atoms[i].type = ARRAY_INDEX;
+ err = parse_rvalue(value, &preset->atoms[i].index);
+ if (err)
+ return err;
+ } else {
+ preset->atoms[i].type = FIELD_NAME;
+ preset->atoms[i].name = strdup(value);
+ if (!preset->atoms[i].name)
+ return -ENOMEM;
+ }
+ return 0;
+}
static int parse_var_atoms(const char *full_var, struct var_preset *preset)
{
- char expr[256], *name, *saveptr;
+ char expr[256], var[256], *name, *saveptr;
+ int n, len, off;
snprintf(expr, sizeof(expr), "%s", full_var);
preset->atom_count = 0;
while ((name = strtok_r(preset->atom_count ? NULL : expr, ".", &saveptr))) {
- struct field_access *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++;
+ len = strlen(name);
+ /* parse variable name */
+ if (sscanf(name, "%[a-zA-Z0-9_] %n", var, &off) != 1) {
+ fprintf(stderr, "Can't parse %s\n", name);
+ return -EINVAL;
+ }
+ append_preset_atom(preset, var, false);
- preset->atoms[i].name = strdup(name);
- if (!preset->atoms[i].name)
- return -ENOMEM;
+ /* parse optional array indexes */
+ while (off < len) {
+ if (sscanf(name + off, " [ %[a-zA-Z0-9_] ] %n", var, &n) != 1) {
+ fprintf(stderr, "Can't parse %s as index\n", name + off);
+ return -EINVAL;
+ }
+ append_preset_atom(preset, var, true);
+ off += n;
+ }
}
return 0;
}
void *tmp;
struct var_preset *cur;
char var[256], val[256];
- int n, err;
+ int n, err, i;
tmp = realloc(*presets, (*cnt + 1) * sizeof(**presets));
if (!tmp)
memset(cur, 0, sizeof(*cur));
(*cnt)++;
- if (sscanf(expr, "%s = %s %n", var, val, &n) != 2 || n != strlen(expr)) {
+ if (sscanf(expr, " %[][a-zA-Z0-9_. ] = %s %n", var, val, &n) != 2 || n != strlen(expr)) {
fprintf(stderr, "Failed to parse expression '%s'\n", expr);
return -EINVAL;
}
+ /* Remove trailing spaces from var, as scanf may add those */
+ for (i = strlen(var) - 1; i > 0; --i) {
+ if (!isspace(var[i]))
+ break;
+ var[i] = '\0';
+ }
err = parse_rvalue(val, &cur->value);
if (err)
return btf_is_int(t) || btf_is_enum(t) || btf_is_enum64(t);
}
-const int btf_find_member(const struct btf *btf,
- const struct btf_type *parent_type,
- __u32 parent_offset,
- const char *member_name,
- int *member_tid,
- __u32 *member_offset)
+static int find_enum_value(const struct btf *btf, const char *name, long long *value)
+{
+ const struct btf_type *t;
+ int cnt, i;
+ long long lvalue;
+
+ cnt = btf__type_cnt(btf);
+ for (i = 1; i != cnt; ++i) {
+ t = btf__type_by_id(btf, i);
+
+ if (!btf_is_any_enum(t))
+ continue;
+
+ if (enum_value_from_name(btf, t, name, &lvalue) == 0) {
+ *value = lvalue;
+ return 0;
+ }
+ }
+ return -ESRCH;
+}
+
+static int resolve_rvalue(struct btf *btf, const struct rvalue *rvalue, long long *result)
+{
+ int err = 0;
+
+ switch (rvalue->type) {
+ case INTEGRAL:
+ *result = rvalue->ivalue;
+ return 0;
+ case ENUMERATOR:
+ err = find_enum_value(btf, rvalue->svalue, result);
+ if (err) {
+ fprintf(stderr, "Can't resolve enum value %s\n", rvalue->svalue);
+ return err;
+ }
+ return 0;
+ default:
+ fprintf(stderr, "Unknown rvalue type\n");
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static int adjust_var_secinfo_array(struct btf *btf, int tid, struct field_access *atom,
+ const char *array_name, struct btf_var_secinfo *sinfo)
+{
+ const struct btf_type *t;
+ struct btf_array *barr;
+ long long idx;
+ int err;
+
+ tid = btf__resolve_type(btf, tid);
+ t = btf__type_by_id(btf, tid);
+ if (!btf_is_array(t)) {
+ fprintf(stderr, "Array index is not expected for %s\n",
+ array_name);
+ return -EINVAL;
+ }
+ barr = btf_array(t);
+ err = resolve_rvalue(btf, &atom->index, &idx);
+ if (err)
+ return err;
+ if (idx < 0 || idx >= barr->nelems) {
+ fprintf(stderr, "Array index %lld is out of bounds [0, %u]: %s\n",
+ idx, barr->nelems, array_name);
+ return -EINVAL;
+ }
+ sinfo->size = btf__resolve_size(btf, barr->type);
+ sinfo->offset += sinfo->size * idx;
+ sinfo->type = btf__resolve_type(btf, barr->type);
+ return 0;
+}
+
+static int adjust_var_secinfo_member(const struct btf *btf,
+ const struct btf_type *parent_type,
+ __u32 parent_offset,
+ const char *member_name,
+ struct btf_var_secinfo *sinfo)
{
int i;
- if (!btf_is_composite(parent_type))
+ if (!btf_is_composite(parent_type)) {
+ fprintf(stderr, "Can't resolve field %s for non-composite type\n", member_name);
return -EINVAL;
+ }
for (i = 0; i < btf_vlen(parent_type); ++i) {
const struct btf_member *member;
const struct btf_type *member_type;
- int tid;
+ int tid, off;
member = btf_members(parent_type) + i;
tid = btf__resolve_type(btf, member->type);
return -EINVAL;
member_type = btf__type_by_id(btf, tid);
+ off = parent_offset + member->offset;
if (member->name_off) {
const char *name = btf__name_by_offset(btf, member->name_off);
name);
return -EINVAL;
}
- *member_offset = parent_offset + member->offset;
- *member_tid = tid;
+ sinfo->offset += off / 8;
+ sinfo->type = tid;
+ sinfo->size = member_type->size;
return 0;
}
} else if (btf_is_composite(member_type)) {
int err;
- err = btf_find_member(btf, member_type, parent_offset + member->offset,
- member_name, member_tid, member_offset);
+ err = adjust_var_secinfo_member(btf, member_type, off,
+ member_name, sinfo);
if (!err)
return 0;
}
static int adjust_var_secinfo(struct btf *btf, const struct btf_type *t,
struct btf_var_secinfo *sinfo, struct var_preset *preset)
{
- const struct btf_type *base_type, *member_type;
- int err, member_tid, i;
- __u32 member_offset = 0;
+ const struct btf_type *base_type;
+ const char *prev_name;
+ int err, i;
+ int tid;
+
+ assert(preset->atom_count > 0);
+ assert(preset->atoms[0].type == FIELD_NAME);
- base_type = btf__type_by_id(btf, btf__resolve_type(btf, t->type));
+ tid = btf__resolve_type(btf, t->type);
+ base_type = btf__type_by_id(btf, tid);
+ prev_name = preset->atoms[0].name;
for (i = 1; i < preset->atom_count; ++i) {
- err = btf_find_member(btf, base_type, 0, preset->atoms[i].name,
- &member_tid, &member_offset);
- if (err) {
- fprintf(stderr, "Could not find member %s for variable %s\n",
- preset->atoms[i].name, preset->atoms[i - 1].name);
- return err;
+ struct field_access *atom = preset->atoms + i;
+
+ switch (atom->type) {
+ case ARRAY_INDEX:
+ err = adjust_var_secinfo_array(btf, tid, atom, prev_name, sinfo);
+ break;
+ case FIELD_NAME:
+ err = adjust_var_secinfo_member(btf, base_type, 0, atom->name, sinfo);
+ prev_name = atom->name;
+ break;
+ default:
+ fprintf(stderr, "Unknown field_access type\n");
+ return -EOPNOTSUPP;
}
- member_type = btf__type_by_id(btf, member_tid);
- sinfo->offset += member_offset / 8;
- sinfo->size = member_type->size;
- sinfo->type = member_tid;
- base_type = member_type;
+ if (err)
+ return err;
+ base_type = btf__type_by_id(btf, sinfo->type);
+ tid = sinfo->type;
}
+
return 0;
}
return -EINVAL;
}
if (!is_preset_supported(base_type)) {
- fprintf(stderr, "Setting value for type %s is not supported\n",
- btf__name_by_offset(btf, base_type->name_off));
+ fprintf(stderr, "Can't set %s. Only ints and enums are supported\n",
+ preset->full_name);
return -EINVAL;
}
if (!presets[i].applied) {
fprintf(stderr, "Global variable preset %s has not been applied\n",
presets[i].full_name);
+ err = -EINVAL;
}
presets[i].applied = false;
}
free(env.deny_filters);
for (i = 0; i < env.npresets; ++i) {
free(env.presets[i].full_name);
- for (j = 0; j < env.presets[i].atom_count; ++j)
- free(env.presets[i].atoms[j].name);
+ for (j = 0; j < env.presets[i].atom_count; ++j) {
+ switch (env.presets[i].atoms[j].type) {
+ case FIELD_NAME:
+ free(env.presets[i].atoms[j].name);
+ break;
+ case ARRAY_INDEX:
+ if (env.presets[i].atoms[j].index.type == ENUMERATOR)
+ free(env.presets[i].atoms[j].index.svalue);
+ break;
+ }
+ }
free(env.presets[i].atoms);
- if (env.presets[i].value.type == ENUMERATOR)
- free(env.presets[i].value.svalue);
}
free(env.presets);
return -err;