1*f50a7f3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 23752e453SMichael Ellerman /* 33752e453SMichael Ellerman * Copyright 2014, Michael Ellerman, IBM Corp. 43752e453SMichael Ellerman */ 53752e453SMichael Ellerman 63752e453SMichael Ellerman #include <errno.h> 73752e453SMichael Ellerman #include <stdio.h> 83752e453SMichael Ellerman #include <stdlib.h> 93752e453SMichael Ellerman #include <string.h> 103752e453SMichael Ellerman #include <sys/mman.h> 113752e453SMichael Ellerman 123752e453SMichael Ellerman #include "trace.h" 133752e453SMichael Ellerman 143752e453SMichael Ellerman 153752e453SMichael Ellerman struct trace_buffer *trace_buffer_allocate(u64 size) 163752e453SMichael Ellerman { 173752e453SMichael Ellerman struct trace_buffer *tb; 183752e453SMichael Ellerman 193752e453SMichael Ellerman if (size < sizeof(*tb)) { 203752e453SMichael Ellerman fprintf(stderr, "Error: trace buffer too small\n"); 213752e453SMichael Ellerman return NULL; 223752e453SMichael Ellerman } 233752e453SMichael Ellerman 243752e453SMichael Ellerman tb = mmap(NULL, size, PROT_READ | PROT_WRITE, 253752e453SMichael Ellerman MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 263752e453SMichael Ellerman if (tb == MAP_FAILED) { 273752e453SMichael Ellerman perror("mmap"); 283752e453SMichael Ellerman return NULL; 293752e453SMichael Ellerman } 303752e453SMichael Ellerman 313752e453SMichael Ellerman tb->size = size; 323752e453SMichael Ellerman tb->tail = tb->data; 333752e453SMichael Ellerman tb->overflow = false; 343752e453SMichael Ellerman 353752e453SMichael Ellerman return tb; 363752e453SMichael Ellerman } 373752e453SMichael Ellerman 383752e453SMichael Ellerman static bool trace_check_bounds(struct trace_buffer *tb, void *p) 393752e453SMichael Ellerman { 403752e453SMichael Ellerman return p < ((void *)tb + tb->size); 413752e453SMichael Ellerman } 423752e453SMichael Ellerman 433752e453SMichael Ellerman static bool trace_check_alloc(struct trace_buffer *tb, void *p) 443752e453SMichael Ellerman { 453752e453SMichael Ellerman /* 463752e453SMichael Ellerman * If we ever overflowed don't allow any more input. This prevents us 473752e453SMichael Ellerman * from dropping a large item and then later logging a small one. The 483752e453SMichael Ellerman * buffer should just stop when overflow happened, not be patchy. If 493752e453SMichael Ellerman * you're overflowing, make your buffer bigger. 503752e453SMichael Ellerman */ 513752e453SMichael Ellerman if (tb->overflow) 523752e453SMichael Ellerman return false; 533752e453SMichael Ellerman 543752e453SMichael Ellerman if (!trace_check_bounds(tb, p)) { 553752e453SMichael Ellerman tb->overflow = true; 563752e453SMichael Ellerman return false; 573752e453SMichael Ellerman } 583752e453SMichael Ellerman 593752e453SMichael Ellerman return true; 603752e453SMichael Ellerman } 613752e453SMichael Ellerman 623752e453SMichael Ellerman static void *trace_alloc(struct trace_buffer *tb, int bytes) 633752e453SMichael Ellerman { 643752e453SMichael Ellerman void *p, *newtail; 653752e453SMichael Ellerman 663752e453SMichael Ellerman p = tb->tail; 673752e453SMichael Ellerman newtail = tb->tail + bytes; 683752e453SMichael Ellerman if (!trace_check_alloc(tb, newtail)) 693752e453SMichael Ellerman return NULL; 703752e453SMichael Ellerman 713752e453SMichael Ellerman tb->tail = newtail; 723752e453SMichael Ellerman 733752e453SMichael Ellerman return p; 743752e453SMichael Ellerman } 753752e453SMichael Ellerman 763752e453SMichael Ellerman static struct trace_entry *trace_alloc_entry(struct trace_buffer *tb, int payload_size) 773752e453SMichael Ellerman { 783752e453SMichael Ellerman struct trace_entry *e; 793752e453SMichael Ellerman 803752e453SMichael Ellerman e = trace_alloc(tb, sizeof(*e) + payload_size); 813752e453SMichael Ellerman if (e) 823752e453SMichael Ellerman e->length = payload_size; 833752e453SMichael Ellerman 843752e453SMichael Ellerman return e; 853752e453SMichael Ellerman } 863752e453SMichael Ellerman 873752e453SMichael Ellerman int trace_log_reg(struct trace_buffer *tb, u64 reg, u64 value) 883752e453SMichael Ellerman { 893752e453SMichael Ellerman struct trace_entry *e; 903752e453SMichael Ellerman u64 *p; 913752e453SMichael Ellerman 923752e453SMichael Ellerman e = trace_alloc_entry(tb, sizeof(reg) + sizeof(value)); 933752e453SMichael Ellerman if (!e) 943752e453SMichael Ellerman return -ENOSPC; 953752e453SMichael Ellerman 963752e453SMichael Ellerman e->type = TRACE_TYPE_REG; 973752e453SMichael Ellerman p = (u64 *)e->data; 983752e453SMichael Ellerman *p++ = reg; 993752e453SMichael Ellerman *p++ = value; 1003752e453SMichael Ellerman 1013752e453SMichael Ellerman return 0; 1023752e453SMichael Ellerman } 1033752e453SMichael Ellerman 1043752e453SMichael Ellerman int trace_log_counter(struct trace_buffer *tb, u64 value) 1053752e453SMichael Ellerman { 1063752e453SMichael Ellerman struct trace_entry *e; 1073752e453SMichael Ellerman u64 *p; 1083752e453SMichael Ellerman 1093752e453SMichael Ellerman e = trace_alloc_entry(tb, sizeof(value)); 1103752e453SMichael Ellerman if (!e) 1113752e453SMichael Ellerman return -ENOSPC; 1123752e453SMichael Ellerman 1133752e453SMichael Ellerman e->type = TRACE_TYPE_COUNTER; 1143752e453SMichael Ellerman p = (u64 *)e->data; 1153752e453SMichael Ellerman *p++ = value; 1163752e453SMichael Ellerman 1173752e453SMichael Ellerman return 0; 1183752e453SMichael Ellerman } 1193752e453SMichael Ellerman 1203752e453SMichael Ellerman int trace_log_string(struct trace_buffer *tb, char *str) 1213752e453SMichael Ellerman { 1223752e453SMichael Ellerman struct trace_entry *e; 1233752e453SMichael Ellerman char *p; 1243752e453SMichael Ellerman int len; 1253752e453SMichael Ellerman 1263752e453SMichael Ellerman len = strlen(str); 1273752e453SMichael Ellerman 1283752e453SMichael Ellerman /* We NULL terminate to make printing easier */ 1293752e453SMichael Ellerman e = trace_alloc_entry(tb, len + 1); 1303752e453SMichael Ellerman if (!e) 1313752e453SMichael Ellerman return -ENOSPC; 1323752e453SMichael Ellerman 1333752e453SMichael Ellerman e->type = TRACE_TYPE_STRING; 1343752e453SMichael Ellerman p = (char *)e->data; 1353752e453SMichael Ellerman memcpy(p, str, len); 1363752e453SMichael Ellerman p += len; 1373752e453SMichael Ellerman *p = '\0'; 1383752e453SMichael Ellerman 1393752e453SMichael Ellerman return 0; 1403752e453SMichael Ellerman } 1413752e453SMichael Ellerman 1423752e453SMichael Ellerman int trace_log_indent(struct trace_buffer *tb) 1433752e453SMichael Ellerman { 1443752e453SMichael Ellerman struct trace_entry *e; 1453752e453SMichael Ellerman 1463752e453SMichael Ellerman e = trace_alloc_entry(tb, 0); 1473752e453SMichael Ellerman if (!e) 1483752e453SMichael Ellerman return -ENOSPC; 1493752e453SMichael Ellerman 1503752e453SMichael Ellerman e->type = TRACE_TYPE_INDENT; 1513752e453SMichael Ellerman 1523752e453SMichael Ellerman return 0; 1533752e453SMichael Ellerman } 1543752e453SMichael Ellerman 1553752e453SMichael Ellerman int trace_log_outdent(struct trace_buffer *tb) 1563752e453SMichael Ellerman { 1573752e453SMichael Ellerman struct trace_entry *e; 1583752e453SMichael Ellerman 1593752e453SMichael Ellerman e = trace_alloc_entry(tb, 0); 1603752e453SMichael Ellerman if (!e) 1613752e453SMichael Ellerman return -ENOSPC; 1623752e453SMichael Ellerman 1633752e453SMichael Ellerman e->type = TRACE_TYPE_OUTDENT; 1643752e453SMichael Ellerman 1653752e453SMichael Ellerman return 0; 1663752e453SMichael Ellerman } 1673752e453SMichael Ellerman 1683752e453SMichael Ellerman static void trace_print_header(int seq, int prefix) 1693752e453SMichael Ellerman { 1703752e453SMichael Ellerman printf("%*s[%d]: ", prefix, "", seq); 1713752e453SMichael Ellerman } 1723752e453SMichael Ellerman 1733752e453SMichael Ellerman static char *trace_decode_reg(int reg) 1743752e453SMichael Ellerman { 1753752e453SMichael Ellerman switch (reg) { 1763752e453SMichael Ellerman case 769: return "SPRN_MMCR2"; break; 1773752e453SMichael Ellerman case 770: return "SPRN_MMCRA"; break; 1783752e453SMichael Ellerman case 779: return "SPRN_MMCR0"; break; 1793752e453SMichael Ellerman case 804: return "SPRN_EBBHR"; break; 1803752e453SMichael Ellerman case 805: return "SPRN_EBBRR"; break; 1813752e453SMichael Ellerman case 806: return "SPRN_BESCR"; break; 1823752e453SMichael Ellerman case 800: return "SPRN_BESCRS"; break; 1833752e453SMichael Ellerman case 801: return "SPRN_BESCRSU"; break; 1843752e453SMichael Ellerman case 802: return "SPRN_BESCRR"; break; 1853752e453SMichael Ellerman case 803: return "SPRN_BESCRRU"; break; 1863752e453SMichael Ellerman case 771: return "SPRN_PMC1"; break; 1873752e453SMichael Ellerman case 772: return "SPRN_PMC2"; break; 1883752e453SMichael Ellerman case 773: return "SPRN_PMC3"; break; 1893752e453SMichael Ellerman case 774: return "SPRN_PMC4"; break; 1903752e453SMichael Ellerman case 775: return "SPRN_PMC5"; break; 1913752e453SMichael Ellerman case 776: return "SPRN_PMC6"; break; 1923752e453SMichael Ellerman case 780: return "SPRN_SIAR"; break; 1933752e453SMichael Ellerman case 781: return "SPRN_SDAR"; break; 1943752e453SMichael Ellerman case 768: return "SPRN_SIER"; break; 1953752e453SMichael Ellerman } 1963752e453SMichael Ellerman 1973752e453SMichael Ellerman return NULL; 1983752e453SMichael Ellerman } 1993752e453SMichael Ellerman 2003752e453SMichael Ellerman static void trace_print_reg(struct trace_entry *e) 2013752e453SMichael Ellerman { 2023752e453SMichael Ellerman u64 *p, *reg, *value; 2033752e453SMichael Ellerman char *name; 2043752e453SMichael Ellerman 2053752e453SMichael Ellerman p = (u64 *)e->data; 2063752e453SMichael Ellerman reg = p++; 2073752e453SMichael Ellerman value = p; 2083752e453SMichael Ellerman 2093752e453SMichael Ellerman name = trace_decode_reg(*reg); 2103752e453SMichael Ellerman if (name) 2113752e453SMichael Ellerman printf("register %-10s = 0x%016llx\n", name, *value); 2123752e453SMichael Ellerman else 2133752e453SMichael Ellerman printf("register %lld = 0x%016llx\n", *reg, *value); 2143752e453SMichael Ellerman } 2153752e453SMichael Ellerman 2163752e453SMichael Ellerman static void trace_print_counter(struct trace_entry *e) 2173752e453SMichael Ellerman { 2183752e453SMichael Ellerman u64 *value; 2193752e453SMichael Ellerman 2203752e453SMichael Ellerman value = (u64 *)e->data; 2213752e453SMichael Ellerman printf("counter = %lld\n", *value); 2223752e453SMichael Ellerman } 2233752e453SMichael Ellerman 2243752e453SMichael Ellerman static void trace_print_string(struct trace_entry *e) 2253752e453SMichael Ellerman { 2263752e453SMichael Ellerman char *str; 2273752e453SMichael Ellerman 2283752e453SMichael Ellerman str = (char *)e->data; 2293752e453SMichael Ellerman puts(str); 2303752e453SMichael Ellerman } 2313752e453SMichael Ellerman 2323752e453SMichael Ellerman #define BASE_PREFIX 2 2333752e453SMichael Ellerman #define PREFIX_DELTA 8 2343752e453SMichael Ellerman 2353752e453SMichael Ellerman static void trace_print_entry(struct trace_entry *e, int seq, int *prefix) 2363752e453SMichael Ellerman { 2373752e453SMichael Ellerman switch (e->type) { 2383752e453SMichael Ellerman case TRACE_TYPE_REG: 2393752e453SMichael Ellerman trace_print_header(seq, *prefix); 2403752e453SMichael Ellerman trace_print_reg(e); 2413752e453SMichael Ellerman break; 2423752e453SMichael Ellerman case TRACE_TYPE_COUNTER: 2433752e453SMichael Ellerman trace_print_header(seq, *prefix); 2443752e453SMichael Ellerman trace_print_counter(e); 2453752e453SMichael Ellerman break; 2463752e453SMichael Ellerman case TRACE_TYPE_STRING: 2473752e453SMichael Ellerman trace_print_header(seq, *prefix); 2483752e453SMichael Ellerman trace_print_string(e); 2493752e453SMichael Ellerman break; 2503752e453SMichael Ellerman case TRACE_TYPE_INDENT: 2513752e453SMichael Ellerman trace_print_header(seq, *prefix); 2523752e453SMichael Ellerman puts("{"); 2533752e453SMichael Ellerman *prefix += PREFIX_DELTA; 2543752e453SMichael Ellerman break; 2553752e453SMichael Ellerman case TRACE_TYPE_OUTDENT: 2563752e453SMichael Ellerman *prefix -= PREFIX_DELTA; 2573752e453SMichael Ellerman if (*prefix < BASE_PREFIX) 2583752e453SMichael Ellerman *prefix = BASE_PREFIX; 2593752e453SMichael Ellerman trace_print_header(seq, *prefix); 2603752e453SMichael Ellerman puts("}"); 2613752e453SMichael Ellerman break; 2623752e453SMichael Ellerman default: 2633752e453SMichael Ellerman trace_print_header(seq, *prefix); 2643752e453SMichael Ellerman printf("entry @ %p type %d\n", e, e->type); 2653752e453SMichael Ellerman break; 2663752e453SMichael Ellerman } 2673752e453SMichael Ellerman } 2683752e453SMichael Ellerman 2693752e453SMichael Ellerman void trace_buffer_print(struct trace_buffer *tb) 2703752e453SMichael Ellerman { 2713752e453SMichael Ellerman struct trace_entry *e; 2723752e453SMichael Ellerman int i, prefix; 2733752e453SMichael Ellerman void *p; 2743752e453SMichael Ellerman 2753752e453SMichael Ellerman printf("Trace buffer dump:\n"); 2763752e453SMichael Ellerman printf(" address %p \n", tb); 2773752e453SMichael Ellerman printf(" tail %p\n", tb->tail); 2783752e453SMichael Ellerman printf(" size %llu\n", tb->size); 2793752e453SMichael Ellerman printf(" overflow %s\n", tb->overflow ? "TRUE" : "false"); 2803752e453SMichael Ellerman printf(" Content:\n"); 2813752e453SMichael Ellerman 2823752e453SMichael Ellerman p = tb->data; 2833752e453SMichael Ellerman 2843752e453SMichael Ellerman i = 0; 2853752e453SMichael Ellerman prefix = BASE_PREFIX; 2863752e453SMichael Ellerman 2873752e453SMichael Ellerman while (trace_check_bounds(tb, p) && p < tb->tail) { 2883752e453SMichael Ellerman e = p; 2893752e453SMichael Ellerman 2903752e453SMichael Ellerman trace_print_entry(e, i, &prefix); 2913752e453SMichael Ellerman 2923752e453SMichael Ellerman i++; 2933752e453SMichael Ellerman p = (void *)e + sizeof(*e) + e->length; 2943752e453SMichael Ellerman } 2953752e453SMichael Ellerman } 2963752e453SMichael Ellerman 2973752e453SMichael Ellerman void trace_print_location(struct trace_buffer *tb) 2983752e453SMichael Ellerman { 2993752e453SMichael Ellerman printf("Trace buffer 0x%llx bytes @ %p\n", tb->size, tb); 3003752e453SMichael Ellerman } 301