#include <sys/resource.h>              /* getrlimit */
 #include <ftw.h>
 #include <sys/stat.h>
+#include <linux/list.h>
 #include "jsmn.h"
 #include "json.h"
 #include "jevents.h"
        return 0;
 }
 
+struct event_struct {
+       struct list_head list;
+       char *name;
+       char *event;
+       char *desc;
+       char *long_desc;
+       char *pmu;
+       char *unit;
+       char *perpkg;
+       char *metric_expr;
+       char *metric_name;
+       char *metric_group;
+};
+
+#define ADD_EVENT_FIELD(field) do { if (field) {               \
+       es->field = strdup(field);                              \
+       if (!es->field)                                         \
+               goto out_free;                                  \
+} } while (0)
+
+#define FREE_EVENT_FIELD(field) free(es->field)
+
+#define TRY_FIXUP_FIELD(field) do { if (es->field && !*field) {\
+       *field = strdup(es->field);                             \
+       if (!*field)                                            \
+               return -ENOMEM;                                 \
+} } while (0)
+
+#define FOR_ALL_EVENT_STRUCT_FIELDS(op) do {                   \
+       op(name);                                               \
+       op(event);                                              \
+       op(desc);                                               \
+       op(long_desc);                                          \
+       op(pmu);                                                \
+       op(unit);                                               \
+       op(perpkg);                                             \
+       op(metric_expr);                                        \
+       op(metric_name);                                        \
+       op(metric_group);                                       \
+} while (0)
+
+static LIST_HEAD(arch_std_events);
+
+static void free_arch_std_events(void)
+{
+       struct event_struct *es, *next;
+
+       list_for_each_entry_safe(es, next, &arch_std_events, list) {
+               FOR_ALL_EVENT_STRUCT_FIELDS(FREE_EVENT_FIELD);
+               list_del(&es->list);
+               free(es);
+       }
+}
+
+static int save_arch_std_events(void *data, char *name, char *event,
+                               char *desc, char *long_desc, char *pmu,
+                               char *unit, char *perpkg, char *metric_expr,
+                               char *metric_name, char *metric_group)
+{
+       struct event_struct *es;
+       struct stat *sb = data;
+
+       es = malloc(sizeof(*es));
+       if (!es)
+               return -ENOMEM;
+       memset(es, 0, sizeof(*es));
+       FOR_ALL_EVENT_STRUCT_FIELDS(ADD_EVENT_FIELD);
+       list_add_tail(&es->list, &arch_std_events);
+       return 0;
+out_free:
+       FOR_ALL_EVENT_STRUCT_FIELDS(FREE_EVENT_FIELD);
+       free(es);
+       return -ENOMEM;
+}
+
 static void print_events_table_suffix(FILE *outfp)
 {
        fprintf(outfp, "{\n");
        return event;
 }
 
+static int
+try_fixup(const char *fn, char *arch_std, char **event, char **desc,
+         char **name, char **long_desc, char **pmu, char **filter,
+         char **perpkg, char **unit, char **metric_expr, char **metric_name,
+         char **metric_group, unsigned long long eventcode)
+{
+       /* try to find matching event from arch standard values */
+       struct event_struct *es;
+
+       list_for_each_entry(es, &arch_std_events, list) {
+               if (!strcmp(arch_std, es->name)) {
+                       if (!eventcode && es->event) {
+                               /* allow EventCode to be overridden */
+                               free(*event);
+                               *event = NULL;
+                       }
+                       FOR_ALL_EVENT_STRUCT_FIELDS(TRY_FIXUP_FIELD);
+                       return 0;
+               }
+       }
+
+       pr_err("%s: could not find matching %s for %s\n",
+                                       prog, arch_std, fn);
+       return -1;
+}
+
 /* Call func with each event in the json file */
 int json_events(const char *fn,
          int (*func)(void *data, char *name, char *event, char *desc,
                char *metric_expr = NULL;
                char *metric_name = NULL;
                char *metric_group = NULL;
+               char *arch_std = NULL;
                unsigned long long eventcode = 0;
                struct msrmap *msr = NULL;
                jsmntok_t *msrval = NULL;
                                addfield(map, &metric_expr, "", "", val);
                                for (s = metric_expr; *s; s++)
                                        *s = tolower(*s);
+                       } else if (json_streq(map, field, "ArchStdEvent")) {
+                               addfield(map, &arch_std, "", "", val);
+                               for (s = arch_std; *s; s++)
+                                       *s = tolower(*s);
                        }
                        /* ignore unknown fields */
                }
                if (name)
                        fixname(name);
 
+               if (arch_std) {
+                       /*
+                        * An arch standard event is referenced, so try to
+                        * fixup any unassigned values.
+                        */
+                       err = try_fixup(fn, arch_std, &event, &desc, &name,
+                                       &long_desc, &pmu, &filter, &perpkg,
+                                       &unit, &metric_expr, &metric_name,
+                                       &metric_group, eventcode);
+                       if (err)
+                               goto free_strings;
+               }
                err = func(data, name, real_event(name, event), desc, long_desc,
                           pmu, unit, perpkg, metric_expr, metric_name, metric_group);
+free_strings:
                free(event);
                free(desc);
                free(name);
                free(metric_expr);
                free(metric_name);
                free(metric_group);
+               free(arch_std);
+
                if (err)
                        break;
                tok += j;
        return res;
 }
 
+static int is_json_file(const char *name)
+{
+       const char *suffix;
+
+       if (strlen(name) < 5)
+               return 0;
+
+       suffix = name + strlen(name) - 5;
+
+       if (strncmp(suffix, ".json", 5) == 0)
+               return 1;
+       return 0;
+}
+
+static int preprocess_arch_std_files(const char *fpath, const struct stat *sb,
+                               int typeflag, struct FTW *ftwbuf)
+{
+       int level = ftwbuf->level;
+       int is_file = typeflag == FTW_F;
+
+       if (level == 1 && is_file && is_json_file(fpath))
+               return json_events(fpath, save_arch_std_events, (void *)sb);
+
+       return 0;
+}
+
 static int process_one_file(const char *fpath, const struct stat *sb,
                            int typeflag, struct FTW *ftwbuf)
 {
         * ignore it. It could be a readme.txt for instance.
         */
        if (is_file) {
-               char *suffix = bname + strlen(bname) - 5;
-
-               if (strncmp(suffix, ".json", 5)) {
+               if (!is_json_file(bname)) {
                        pr_info("%s: Ignoring file without .json suffix %s\n", prog,
                                fpath);
                        return 0;
 
        maxfds = get_maxfds();
        mapfile = NULL;
+       rc = nftw(ldirname, preprocess_arch_std_files, maxfds, 0);
+       if (rc && verbose) {
+               pr_info("%s: Error preprocessing arch standard files %s\n",
+                       prog, ldirname);
+               goto empty_map;
+       } else if (rc < 0) {
+               /* Make build fail */
+               free_arch_std_events();
+               return 1;
+       } else if (rc) {
+               goto empty_map;
+       }
+
        rc = nftw(ldirname, process_one_file, maxfds, 0);
        if (rc && verbose) {
                pr_info("%s: Error walking file tree %s\n", prog, ldirname);
                goto empty_map;
        } else if (rc < 0) {
                /* Make build fail */
+               free_arch_std_events();
                return 1;
        } else if (rc) {
                goto empty_map;
 empty_map:
        fclose(eventsfp);
        create_empty_mapping(output_file);
+       free_arch_std_events();
        return 0;
 }