{.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF},
 };
 
+enum {
+       OUTPUT_TYPE_SYNTH = PERF_TYPE_MAX,
+       OUTPUT_TYPE_MAX
+};
+
 /* default set to maintain compatibility with current format */
 static struct {
        bool user_set;
        unsigned int print_ip_opts;
        u64 fields;
        u64 invalid_fields;
-} output[PERF_TYPE_MAX] = {
+} output[OUTPUT_TYPE_MAX] = {
 
        [PERF_TYPE_HARDWARE] = {
                .user_set = false,
 
                .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
        },
+
+       [OUTPUT_TYPE_SYNTH] = {
+               .user_set = false,
+
+               .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
+                             PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
+                             PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
+                             PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,
+
+               .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
+       },
 };
 
+static inline int output_type(unsigned int type)
+{
+       switch (type) {
+       case PERF_TYPE_SYNTH:
+               return OUTPUT_TYPE_SYNTH;
+       default:
+               return type;
+       }
+}
+
+static inline unsigned int attr_type(unsigned int type)
+{
+       switch (type) {
+       case OUTPUT_TYPE_SYNTH:
+               return PERF_TYPE_SYNTH;
+       default:
+               return type;
+       }
+}
+
 static bool output_set_by_user(void)
 {
        int j;
-       for (j = 0; j < PERF_TYPE_MAX; ++j) {
+       for (j = 0; j < OUTPUT_TYPE_MAX; ++j) {
                if (output[j].user_set)
                        return true;
        }
        return str;
 }
 
-#define PRINT_FIELD(x)  (output[attr->type].fields & PERF_OUTPUT_##x)
+#define PRINT_FIELD(x)  (output[output_type(attr->type)].fields & PERF_OUTPUT_##x)
 
 static int perf_evsel__do_check_stype(struct perf_evsel *evsel,
                                      u64 sample_type, const char *sample_msg,
                                      bool allow_user_set)
 {
        struct perf_event_attr *attr = &evsel->attr;
-       int type = attr->type;
+       int type = output_type(attr->type);
        const char *evname;
 
        if (attr->sample_type & sample_type)
 
 static void set_print_ip_opts(struct perf_event_attr *attr)
 {
-       unsigned int type = attr->type;
+       unsigned int type = output_type(attr->type);
 
        output[type].print_ip_opts = 0;
        if (PRINT_FIELD(IP))
        unsigned int j;
        struct perf_evsel *evsel;
 
-       for (j = 0; j < PERF_TYPE_MAX; ++j) {
-               evsel = perf_session__find_first_evtype(session, j);
+       for (j = 0; j < OUTPUT_TYPE_MAX; ++j) {
+               evsel = perf_session__find_first_evtype(session, attr_type(j));
 
                /*
                 * even if fields is set to 0 (ie., show nothing) event must
                 * exist if user explicitly includes it on the command line
                 */
-               if (!evsel && output[j].user_set && !output[j].wildcard_set) {
+               if (!evsel && output[j].user_set && !output[j].wildcard_set &&
+                   j != OUTPUT_TYPE_SYNTH) {
                        pr_err("%s events do not exist. "
                               "Remove corresponding -F option to proceed.\n",
                               event_type(j));
                             struct machine *machine)
 {
        struct perf_event_attr *attr = &evsel->attr;
+       unsigned int type = output_type(attr->type);
        bool print_srcline_last = false;
 
        if (PRINT_FIELD(CALLINDENT))
 
        /* print branch_from information */
        if (PRINT_FIELD(IP)) {
-               unsigned int print_opts = output[attr->type].print_ip_opts;
+               unsigned int print_opts = output[type].print_ip_opts;
                struct callchain_cursor *cursor = NULL;
 
                if (symbol_conf.use_callchain && sample->callchain &&
        /* print branch_to information */
        if (PRINT_FIELD(ADDR) ||
            ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
-            !output[attr->type].user_set)) {
+            !output[type].user_set)) {
                printf(" => ");
                print_sample_addr(sample, thread, attr);
        }
 {
        struct thread *thread = al->thread;
        struct perf_event_attr *attr = &evsel->attr;
+       unsigned int type = output_type(attr->type);
 
-       if (output[attr->type].fields == 0)
+       if (output[type].fields == 0)
                return;
 
        print_sample_start(sample, thread, evsel);
                        cursor = &callchain_cursor;
 
                putchar(cursor ? '\n' : ' ');
-               sample__fprintf_sym(sample, al, 0, output[attr->type].print_ip_opts, cursor, stdout);
+               sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor, stdout);
        }
 
        if (PRINT_FIELD(IREGS))
        evlist = *pevlist;
        evsel = perf_evlist__last(*pevlist);
 
-       if (evsel->attr.type >= PERF_TYPE_MAX)
+       if (evsel->attr.type >= PERF_TYPE_MAX &&
+           evsel->attr.type != PERF_TYPE_SYNTH)
                return 0;
 
        evlist__for_each_entry(evlist, pos) {
                        type = PERF_TYPE_RAW;
                else if (!strcmp(str, "break"))
                        type = PERF_TYPE_BREAKPOINT;
+               else if (!strcmp(str, "synth"))
+                       type = OUTPUT_TYPE_SYNTH;
                else {
                        fprintf(stderr, "Invalid event type in field string.\n");
                        rc = -EINVAL;
                if (output_set_by_user())
                        pr_warning("Overriding previous field request for all events.\n");
 
-               for (j = 0; j < PERF_TYPE_MAX; ++j) {
+               for (j = 0; j < OUTPUT_TYPE_MAX; ++j) {
                        output[j].fields = 0;
                        output[j].user_set = true;
                        output[j].wildcard_set = true;
                        /* add user option to all events types for
                         * which it is valid
                         */
-                       for (j = 0; j < PERF_TYPE_MAX; ++j) {
+                       for (j = 0; j < OUTPUT_TYPE_MAX; ++j) {
                                if (output[j].invalid_fields & all_output_options[i].field) {
                                        pr_warning("\'%s\' not valid for %s events. Ignoring.\n",
                                                   all_output_options[i].str, event_type(j));
        OPT_CALLBACK('F', "fields", NULL, "str",
                     "comma separated output fields prepend with 'type:'. "
                     "+field to add and -field to remove."
-                    "Valid types: hw,sw,trace,raw. "
+                    "Valid types: hw,sw,trace,raw,synth. "
                     "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
                     "addr,symoff,period,iregs,brstack,brstacksym,flags,"
                     "bpf-output,callindent,insn,insnlen,brstackinsn",