void perf_env__exit(struct perf_env *env)
 {
-       int i;
+       int i, j;
 
        perf_env__purge_bpf(env);
        perf_env__purge_cgroups(env);
        zfree(&env->sibling_threads);
        zfree(&env->pmu_mappings);
        zfree(&env->cpu);
+       for (i = 0; i < env->nr_cpu_pmu_caps; i++)
+               zfree(&env->cpu_pmu_caps[i]);
        zfree(&env->cpu_pmu_caps);
        zfree(&env->numa_map);
 
        zfree(&env->hybrid_nodes);
 
        for (i = 0; i < env->nr_hybrid_cpc_nodes; i++) {
+               for (j = 0; j < env->hybrid_cpc_nodes[i].nr_cpu_pmu_caps; j++)
+                       zfree(&env->hybrid_cpc_nodes[i].cpu_pmu_caps[j]);
                zfree(&env->hybrid_cpc_nodes[i].cpu_pmu_caps);
                zfree(&env->hybrid_cpc_nodes[i].pmu_name);
        }
 
                ff->ph->env.comp_level, ff->ph->env.comp_ratio);
 }
 
-static void print_per_cpu_pmu_caps(FILE *fp, int nr_caps, char *cpu_pmu_caps,
+static void print_per_cpu_pmu_caps(FILE *fp, int nr_caps, char **cpu_pmu_caps,
                                   char *pmu_name)
 {
-       const char *delimiter;
-       char *str, buf[128];
+       const char *delimiter = "";
+       int i;
 
        if (!nr_caps) {
                fprintf(fp, "# %s pmu capabilities: not available\n", pmu_name);
                return;
        }
 
-       scnprintf(buf, sizeof(buf), "# %s pmu capabilities: ", pmu_name);
-
-       delimiter = buf;
-
-       str = cpu_pmu_caps;
-       while (nr_caps--) {
-               fprintf(fp, "%s%s", delimiter, str);
+       fprintf(fp, "# %s pmu capabilities: ", pmu_name);
+       for (i = 0; i < nr_caps; i++) {
+               fprintf(fp, "%s%s", delimiter, cpu_pmu_caps[i]);
                delimiter = ", ";
-               str += strlen(str) + 1;
        }
 
        fprintf(fp, "\n");
 }
 
 static int process_per_cpu_pmu_caps(struct feat_fd *ff, int *nr_cpu_pmu_caps,
-                                   char **cpu_pmu_caps,
+                                   char ***cpu_pmu_caps,
                                    unsigned int *max_branches)
 {
-       char *name, *value;
-       struct strbuf sb;
-       u32 nr_caps;
+       char *name, *value, *ptr;
+       u32 nr_caps, i;
+
+       *nr_cpu_pmu_caps = 0;
+       *cpu_pmu_caps = NULL;
 
        if (do_read_u32(ff, &nr_caps))
                return -1;
 
-       if (!nr_caps) {
-               pr_debug("cpu pmu capabilities not available\n");
+       if (!nr_caps)
                return 0;
-       }
-
-       *nr_cpu_pmu_caps = nr_caps;
 
-       if (strbuf_init(&sb, 128) < 0)
+       *cpu_pmu_caps = zalloc(sizeof(char *) * nr_caps);
+       if (!*cpu_pmu_caps)
                return -1;
 
-       while (nr_caps--) {
+       for (i = 0; i < nr_caps; i++) {
                name = do_read_string(ff);
                if (!name)
                        goto error;
                if (!value)
                        goto free_name;
 
-               if (strbuf_addf(&sb, "%s=%s", name, value) < 0)
+               if (asprintf(&ptr, "%s=%s", name, value) < 0)
                        goto free_value;
 
-               /* include a NULL character at the end */
-               if (strbuf_add(&sb, "", 1) < 0)
-                       goto free_value;
+               (*cpu_pmu_caps)[i] = ptr;
 
                if (!strcmp(name, "branches"))
                        *max_branches = atoi(value);
                free(value);
                free(name);
        }
-       *cpu_pmu_caps = strbuf_detach(&sb, NULL);
+       *nr_cpu_pmu_caps = nr_caps;
        return 0;
 
 free_value:
 free_name:
        free(name);
 error:
-       strbuf_release(&sb);
+       for (; i > 0; i--)
+               free((*cpu_pmu_caps)[i - 1]);
+       free(*cpu_pmu_caps);
+       *cpu_pmu_caps = NULL;
+       *nr_cpu_pmu_caps = 0;
        return -1;
 }
 
 static int process_cpu_pmu_caps(struct feat_fd *ff,
                                void *data __maybe_unused)
 {
-       return process_per_cpu_pmu_caps(ff, &ff->ph->env.nr_cpu_pmu_caps,
+       int ret = process_per_cpu_pmu_caps(ff, &ff->ph->env.nr_cpu_pmu_caps,
                                        &ff->ph->env.cpu_pmu_caps,
                                        &ff->ph->env.max_branches);
+
+       if (!ret && !ff->ph->env.cpu_pmu_caps)
+               pr_debug("cpu pmu capabilities not available\n");
+       return ret;
 }
 
 static int process_hybrid_cpu_pmu_caps(struct feat_fd *ff,
        struct hybrid_cpc_node *nodes;
        u32 nr_pmu, i;
        int ret;
+       int j;
 
        if (do_read_u32(ff, &nr_pmu))
                return -1;
                        ret = -1;
                        goto err;
                }
+               if (!n->nr_cpu_pmu_caps)
+                       pr_debug("%s pmu capabilities not available\n", n->pmu_name);
        }
 
        ff->ph->env.nr_hybrid_cpc_nodes = nr_pmu;
 
 err:
        for (i = 0; i < nr_pmu; i++) {
+               for (j = 0; j < nodes[i].nr_cpu_pmu_caps; j++)
+                       free(nodes[i].cpu_pmu_caps[j]);
                free(nodes[i].cpu_pmu_caps);
                free(nodes[i].pmu_name);
        }