root/tools/testing/selftests/powerpc/pmu/ebb/trace.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. trace_buffer_allocate
  2. trace_check_bounds
  3. trace_check_alloc
  4. trace_alloc
  5. trace_alloc_entry
  6. trace_log_reg
  7. trace_log_counter
  8. trace_log_string
  9. trace_log_indent
  10. trace_log_outdent
  11. trace_print_header
  12. trace_decode_reg
  13. trace_print_reg
  14. trace_print_counter
  15. trace_print_string
  16. trace_print_entry
  17. trace_buffer_print
  18. trace_print_location

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright 2014, Michael Ellerman, IBM Corp.
   4  */
   5 
   6 #include <errno.h>
   7 #include <stdio.h>
   8 #include <stdlib.h>
   9 #include <string.h>
  10 #include <sys/mman.h>
  11 
  12 #include "trace.h"
  13 
  14 
  15 struct trace_buffer *trace_buffer_allocate(u64 size)
  16 {
  17         struct trace_buffer *tb;
  18 
  19         if (size < sizeof(*tb)) {
  20                 fprintf(stderr, "Error: trace buffer too small\n");
  21                 return NULL;
  22         }
  23 
  24         tb = mmap(NULL, size, PROT_READ | PROT_WRITE,
  25                   MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
  26         if (tb == MAP_FAILED) {
  27                 perror("mmap");
  28                 return NULL;
  29         }
  30 
  31         tb->size = size;
  32         tb->tail = tb->data;
  33         tb->overflow = false;
  34 
  35         return tb;
  36 }
  37 
  38 static bool trace_check_bounds(struct trace_buffer *tb, void *p)
  39 {
  40         return p < ((void *)tb + tb->size);
  41 }
  42 
  43 static bool trace_check_alloc(struct trace_buffer *tb, void *p)
  44 {
  45         /*
  46          * If we ever overflowed don't allow any more input. This prevents us
  47          * from dropping a large item and then later logging a small one. The
  48          * buffer should just stop when overflow happened, not be patchy. If
  49          * you're overflowing, make your buffer bigger.
  50          */
  51         if (tb->overflow)
  52                 return false;
  53 
  54         if (!trace_check_bounds(tb, p)) {
  55                 tb->overflow = true;
  56                 return false;
  57         }
  58 
  59         return true;
  60 }
  61 
  62 static void *trace_alloc(struct trace_buffer *tb, int bytes)
  63 {
  64         void *p, *newtail;
  65 
  66         p = tb->tail;
  67         newtail = tb->tail + bytes;
  68         if (!trace_check_alloc(tb, newtail))
  69                 return NULL;
  70 
  71         tb->tail = newtail;
  72 
  73         return p;
  74 }
  75 
  76 static struct trace_entry *trace_alloc_entry(struct trace_buffer *tb, int payload_size)
  77 {
  78         struct trace_entry *e;
  79 
  80         e = trace_alloc(tb, sizeof(*e) + payload_size);
  81         if (e)
  82                 e->length = payload_size;
  83 
  84         return e;
  85 }
  86 
  87 int trace_log_reg(struct trace_buffer *tb, u64 reg, u64 value)
  88 {
  89         struct trace_entry *e;
  90         u64 *p;
  91 
  92         e = trace_alloc_entry(tb, sizeof(reg) + sizeof(value));
  93         if (!e)
  94                 return -ENOSPC;
  95 
  96         e->type = TRACE_TYPE_REG;
  97         p = (u64 *)e->data;
  98         *p++ = reg;
  99         *p++ = value;
 100 
 101         return 0;
 102 }
 103 
 104 int trace_log_counter(struct trace_buffer *tb, u64 value)
 105 {
 106         struct trace_entry *e;
 107         u64 *p;
 108 
 109         e = trace_alloc_entry(tb, sizeof(value));
 110         if (!e)
 111                 return -ENOSPC;
 112 
 113         e->type = TRACE_TYPE_COUNTER;
 114         p = (u64 *)e->data;
 115         *p++ = value;
 116 
 117         return 0;
 118 }
 119 
 120 int trace_log_string(struct trace_buffer *tb, char *str)
 121 {
 122         struct trace_entry *e;
 123         char *p;
 124         int len;
 125 
 126         len = strlen(str);
 127 
 128         /* We NULL terminate to make printing easier */
 129         e = trace_alloc_entry(tb, len + 1);
 130         if (!e)
 131                 return -ENOSPC;
 132 
 133         e->type = TRACE_TYPE_STRING;
 134         p = (char *)e->data;
 135         memcpy(p, str, len);
 136         p += len;
 137         *p = '\0';
 138 
 139         return 0;
 140 }
 141 
 142 int trace_log_indent(struct trace_buffer *tb)
 143 {
 144         struct trace_entry *e;
 145 
 146         e = trace_alloc_entry(tb, 0);
 147         if (!e)
 148                 return -ENOSPC;
 149 
 150         e->type = TRACE_TYPE_INDENT;
 151 
 152         return 0;
 153 }
 154 
 155 int trace_log_outdent(struct trace_buffer *tb)
 156 {
 157         struct trace_entry *e;
 158 
 159         e = trace_alloc_entry(tb, 0);
 160         if (!e)
 161                 return -ENOSPC;
 162 
 163         e->type = TRACE_TYPE_OUTDENT;
 164 
 165         return 0;
 166 }
 167 
 168 static void trace_print_header(int seq, int prefix)
 169 {
 170         printf("%*s[%d]: ", prefix, "", seq);
 171 }
 172 
 173 static char *trace_decode_reg(int reg)
 174 {
 175         switch (reg) {
 176                 case 769: return "SPRN_MMCR2"; break;
 177                 case 770: return "SPRN_MMCRA"; break;
 178                 case 779: return "SPRN_MMCR0"; break;
 179                 case 804: return "SPRN_EBBHR"; break;
 180                 case 805: return "SPRN_EBBRR"; break;
 181                 case 806: return "SPRN_BESCR"; break;
 182                 case 800: return "SPRN_BESCRS"; break;
 183                 case 801: return "SPRN_BESCRSU"; break;
 184                 case 802: return "SPRN_BESCRR"; break;
 185                 case 803: return "SPRN_BESCRRU"; break;
 186                 case 771: return "SPRN_PMC1"; break;
 187                 case 772: return "SPRN_PMC2"; break;
 188                 case 773: return "SPRN_PMC3"; break;
 189                 case 774: return "SPRN_PMC4"; break;
 190                 case 775: return "SPRN_PMC5"; break;
 191                 case 776: return "SPRN_PMC6"; break;
 192                 case 780: return "SPRN_SIAR"; break;
 193                 case 781: return "SPRN_SDAR"; break;
 194                 case 768: return "SPRN_SIER"; break;
 195         }
 196 
 197         return NULL;
 198 }
 199 
 200 static void trace_print_reg(struct trace_entry *e)
 201 {
 202         u64 *p, *reg, *value;
 203         char *name;
 204 
 205         p = (u64 *)e->data;
 206         reg = p++;
 207         value = p;
 208 
 209         name = trace_decode_reg(*reg);
 210         if (name)
 211                 printf("register %-10s = 0x%016llx\n", name, *value);
 212         else
 213                 printf("register %lld = 0x%016llx\n", *reg, *value);
 214 }
 215 
 216 static void trace_print_counter(struct trace_entry *e)
 217 {
 218         u64 *value;
 219 
 220         value = (u64 *)e->data;
 221         printf("counter = %lld\n", *value);
 222 }
 223 
 224 static void trace_print_string(struct trace_entry *e)
 225 {
 226         char *str;
 227 
 228         str = (char *)e->data;
 229         puts(str);
 230 }
 231 
 232 #define BASE_PREFIX     2
 233 #define PREFIX_DELTA    8
 234 
 235 static void trace_print_entry(struct trace_entry *e, int seq, int *prefix)
 236 {
 237         switch (e->type) {
 238         case TRACE_TYPE_REG:
 239                 trace_print_header(seq, *prefix);
 240                 trace_print_reg(e);
 241                 break;
 242         case TRACE_TYPE_COUNTER:
 243                 trace_print_header(seq, *prefix);
 244                 trace_print_counter(e);
 245                 break;
 246         case TRACE_TYPE_STRING:
 247                 trace_print_header(seq, *prefix);
 248                 trace_print_string(e);
 249                 break;
 250         case TRACE_TYPE_INDENT:
 251                 trace_print_header(seq, *prefix);
 252                 puts("{");
 253                 *prefix += PREFIX_DELTA;
 254                 break;
 255         case TRACE_TYPE_OUTDENT:
 256                 *prefix -= PREFIX_DELTA;
 257                 if (*prefix < BASE_PREFIX)
 258                         *prefix = BASE_PREFIX;
 259                 trace_print_header(seq, *prefix);
 260                 puts("}");
 261                 break;
 262         default:
 263                 trace_print_header(seq, *prefix);
 264                 printf("entry @ %p type %d\n", e, e->type);
 265                 break;
 266         }
 267 }
 268 
 269 void trace_buffer_print(struct trace_buffer *tb)
 270 {
 271         struct trace_entry *e;
 272         int i, prefix;
 273         void *p;
 274 
 275         printf("Trace buffer dump:\n");
 276         printf("  address  %p \n", tb);
 277         printf("  tail     %p\n", tb->tail);
 278         printf("  size     %llu\n", tb->size);
 279         printf("  overflow %s\n", tb->overflow ? "TRUE" : "false");
 280         printf("  Content:\n");
 281 
 282         p = tb->data;
 283 
 284         i = 0;
 285         prefix = BASE_PREFIX;
 286 
 287         while (trace_check_bounds(tb, p) && p < tb->tail) {
 288                 e = p;
 289 
 290                 trace_print_entry(e, i, &prefix);
 291 
 292                 i++;
 293                 p = (void *)e + sizeof(*e) + e->length;
 294         }
 295 }
 296 
 297 void trace_print_location(struct trace_buffer *tb)
 298 {
 299         printf("Trace buffer 0x%llx bytes @ %p\n", tb->size, tb);
 300 }

/* [<][>][^][v][top][bottom][index][help] */