return ret;
}
-static int process_feature_event(const struct perf_tool *tool __maybe_unused,
- struct perf_session *session,
- union perf_event *event)
-{
- if (event->feat.feat_id < HEADER_LAST_FEATURE)
- return perf_event__process_feature(session, event);
- return 0;
-}
-
static int hist_entry__stdio_annotate(struct hist_entry *he,
struct evsel *evsel,
struct perf_annotate *ann)
annotate.tool.id_index = perf_event__process_id_index;
annotate.tool.auxtrace_info = perf_event__process_auxtrace_info;
annotate.tool.auxtrace = perf_event__process_auxtrace;
- annotate.tool.feature = process_feature_event;
+ annotate.tool.feature = perf_event__process_feature;
annotate.tool.ordering_requires_timestamps = true;
annotate.session = perf_session__new(&data, &annotate.tool);
union perf_event *event)
{
struct report *rep = container_of(tool, struct report, tool);
+ int ret = perf_event__process_feature(tool, session, event);
- if (event->feat.feat_id < HEADER_LAST_FEATURE)
- return perf_event__process_feature(session, event);
+ if (ret == 0 && event->header.size == sizeof(struct perf_record_header_feature) &&
+ (int)event->feat.feat_id >= session->header.last_feat) {
+ /*
+ * (feat_id = HEADER_LAST_FEATURE) is the end marker which means
+ * all features are received.
+ */
+ if (rep->header_only)
+ session_done = 1;
- if (event->feat.feat_id != HEADER_LAST_FEATURE) {
- pr_err("failed: wrong feature ID: %" PRI_lu64 "\n",
- event->feat.feat_id);
- return -1;
- } else if (rep->header_only) {
- session_done = 1;
+ setup_forced_leader(rep, session->evlist);
}
-
- /*
- * (feat_id = HEADER_LAST_FEATURE) is the end marker which
- * means all features are received, now we can force the
- * group if needed.
- */
- setup_forced_leader(rep, session->evlist);
- return 0;
+ return ret;
}
static int process_sample_event(const struct perf_tool *tool,
return set_maps(script);
}
-static int process_feature_event(const struct perf_tool *tool __maybe_unused,
- struct perf_session *session,
- union perf_event *event)
-{
- if (event->feat.feat_id < HEADER_LAST_FEATURE)
- return perf_event__process_feature(session, event);
- return 0;
-}
-
static int perf_script__process_auxtrace_info(const struct perf_tool *tool,
struct perf_session *session,
union perf_event *event)
#ifdef HAVE_LIBTRACEEVENT
script.tool.tracing_data = perf_event__process_tracing_data;
#endif
- script.tool.feature = process_feature_event;
+ script.tool.feature = perf_event__process_feature;
script.tool.build_id = perf_event__process_build_id;
script.tool.id_index = perf_event__process_id_index;
script.tool.auxtrace_info = perf_script__process_auxtrace_info;
struct convert *c = container_of(tool, struct convert, tool);
struct ctf_writer *cw = &c->writer;
struct perf_record_header_feature *fe = &event->feat;
+ int ret = perf_event__process_feature(tool, session, event);
- if (event->feat.feat_id < HEADER_LAST_FEATURE) {
- int ret = perf_event__process_feature(session, event);
-
- if (ret)
- return ret;
- }
+ if (ret)
+ return ret;
switch (fe->feat_id) {
case HEADER_HOSTNAME:
output_json_format(out, false, 2, "]");
}
-static int process_feature_event(const struct perf_tool *tool __maybe_unused,
- struct perf_session *session,
- union perf_event *event)
-{
- if (event->feat.feat_id < HEADER_LAST_FEATURE)
- return perf_event__process_feature(session, event);
-
- return 0;
-}
-
int bt_convert__perf2json(const char *input_name, const char *output_name,
struct perf_data_convert_opts *opts __maybe_unused)
{
c.tool.auxtrace = perf_event__process_auxtrace;
c.tool.event_update = perf_event__process_event_update;
c.tool.attr = perf_event__process_attr;
- c.tool.feature = process_feature_event;
+ c.tool.feature = perf_event__process_feature;
c.tool.ordering_requires_timestamps = true;
if (opts->all) {
struct feat_fd ff;
if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
- pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
- "%d, continuing...\n", section->offset, feat);
+ pr_debug("Failed to lseek to %" PRIu64 " offset for feature %s (%d), continuing...\n",
+ section->offset, header_feat__name(feat), feat);
return 0;
}
- if (feat >= HEADER_LAST_FEATURE) {
+ if (feat >= ph->last_feat) {
pr_warning("unknown feature %d\n", feat);
return 0;
}
return 0;
fprintf(fp, "# missing features: ");
- for_each_clear_bit(bit, header->adds_features, HEADER_LAST_FEATURE) {
+ for_each_clear_bit(bit, header->adds_features, header->last_feat) {
if (bit)
fprintf(fp, "%s ", feat_ops[bit].name);
}
if (err < 0)
goto out_free;
- for_each_set_bit(feat, header->adds_features, HEADER_LAST_FEATURE) {
+ for_each_set_bit(feat, header->adds_features, header->last_feat) {
err = process(sec++, header, feat, fd, data);
if (err < 0)
goto out_free;
ph->data_offset = header->data.offset;
ph->data_size = header->data.size;
ph->feat_offset = header->data.offset + header->data.size;
+ ph->last_feat = HEADER_LAST_FEATURE;
return 0;
}
};
if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
- pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
- "%d, continuing...\n", section->offset, feat);
+ pr_debug("Failed to lseek to %" PRIu64 " offset for feature %s (%d), continuing...\n",
+ section->offset, header_feat__name(feat), feat);
return 0;
}
if (ph->needs_swap)
header->size = bswap_64(header->size);
+ /* The last feature is written out as a 0 sized event and will update this value. */
+ ph->last_feat = 0;
return 0;
}
return -ENOMEM;
}
-int perf_event__process_feature(struct perf_session *session,
+int perf_event__process_feature(const struct perf_tool *tool __maybe_unused,
+ struct perf_session *session,
union perf_event *event)
{
struct feat_fd ff = { .fd = 0 };
struct perf_record_header_feature *fe = (struct perf_record_header_feature *)event;
+ struct perf_header *header = &session->header;
int type = fe->header.type;
- u64 feat = fe->feat_id;
+ int feat = (int)fe->feat_id;
int ret = 0;
bool print = dump_trace;
+ bool last_feature_mark = false;
if (type < 0 || type >= PERF_RECORD_HEADER_MAX) {
pr_warning("invalid record type %d in pipe-mode\n", type);
return 0;
}
- if (feat == HEADER_RESERVED || feat >= HEADER_LAST_FEATURE) {
- pr_warning("invalid record type %d in pipe-mode\n", type);
+ if (feat == HEADER_RESERVED) {
+ pr_warning("invalid reserved record type in pipe-mode\n");
+ return -1;
+ }
+ if (feat < 0 || feat == INT_MAX) {
+ pr_warning("invalid value for feature type %x\n", feat);
+ return -1;
+ }
+ if (feat >= header->last_feat) {
+ if (event->header.size == sizeof(*fe)) {
+ /*
+ * Either an unexpected zero size feature or the
+ * HEADER_LAST_FEATURE mark.
+ */
+ if (feat > header->last_feat)
+ header->last_feat = min(feat, HEADER_LAST_FEATURE);
+ last_feature_mark = true;
+ } else {
+ /*
+ * A feature but beyond what is known as in
+ * bounds. Assume the last feature is 1 beyond this
+ * feature.
+ */
+ session->header.last_feat = min(feat + 1, HEADER_LAST_FEATURE);
+ }
+ }
+ if (feat >= HEADER_LAST_FEATURE) {
+ if (!last_feature_mark) {
+ pr_warning("unknown feature %d for data file version (%s) in this version of perf (%s)\n",
+ feat, header->env.version, perf_version_string);
+ }
+ return 0;
+ }
+ if (event->header.size < sizeof(*fe)) {
+ pr_warning("feature header size too small\n");
return -1;
}
-
ff.buf = (void *)fe->data;
ff.size = event->header.size - sizeof(*fe);
- ff.ph = &session->header;
+ ff.ph = header;
if (feat_ops[feat].process && feat_ops[feat].process(&ff, NULL)) {
- ret = -1;
+ // Processing failed, ignore when this is the last feature mark.
+ if (!last_feature_mark)
+ ret = -1;
goto out;
}
u64 data_size;
u64 feat_offset;
DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
+ int last_feat;
struct perf_env env;
};
int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full);
-int perf_event__process_feature(struct perf_session *session,
+int perf_event__process_feature(const struct perf_tool *tool,
+ struct perf_session *session,
union perf_event *event);
int perf_event__process_attr(const struct perf_tool *tool, union perf_event *event,
struct evlist **pevlist);
return 0;
}
-static int process_feature_event(const struct perf_tool *tool __maybe_unused,
- struct perf_session *session,
- union perf_event *event)
-{
- if (event->feat.feat_id < HEADER_LAST_FEATURE)
- return perf_event__process_feature(session, event);
- return 0;
-}
-
static void *__sample_reader(void *arg __maybe_unused)
{
struct perf_session *session;
perf_tool__init(&tool, /*ordered_events=*/false);
tool.sample = process_sample_event;
- tool.feature = process_feature_event;
+ tool.feature = perf_event__process_feature;
tool.attr = perf_event__process_attr;
session = perf_session__new(&data, &tool);