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