11b4822a4SAttilio Rao /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 31de7b4b8SPedro F. Giffuni * 41b4822a4SAttilio Rao * Copyright (c) 2008 Nokia Corporation 51b4822a4SAttilio Rao * All rights reserved. 61b4822a4SAttilio Rao * 71b4822a4SAttilio Rao * This software was developed by Attilio Rao for the IPSO project under 81b4822a4SAttilio Rao * contract to Nokia Corporation. 91b4822a4SAttilio Rao * 101b4822a4SAttilio Rao * Redistribution and use in source and binary forms, with or without 111b4822a4SAttilio Rao * modification, are permitted provided that the following conditions 121b4822a4SAttilio Rao * are met: 131b4822a4SAttilio Rao * 1. Redistributions of source code must retain the above copyright 141b4822a4SAttilio Rao * notice unmodified, this list of conditions, and the following 151b4822a4SAttilio Rao * disclaimer. 161b4822a4SAttilio Rao * 2. Redistributions in binary form must reproduce the above copyright 171b4822a4SAttilio Rao * notice, this list of conditions and the following disclaimer in the 181b4822a4SAttilio Rao * documentation and/or other materials provided with the distribution. 191b4822a4SAttilio Rao * 201b4822a4SAttilio Rao * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 211b4822a4SAttilio Rao * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 221b4822a4SAttilio Rao * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 231b4822a4SAttilio Rao * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 241b4822a4SAttilio Rao * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 251b4822a4SAttilio Rao * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 261b4822a4SAttilio Rao * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 271b4822a4SAttilio Rao * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 281b4822a4SAttilio Rao * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 291b4822a4SAttilio Rao * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 301b4822a4SAttilio Rao * 311b4822a4SAttilio Rao */ 321b4822a4SAttilio Rao 331b4822a4SAttilio Rao #include <sys/param.h> 341b4822a4SAttilio Rao #include <sys/queue.h> 351b4822a4SAttilio Rao 361b4822a4SAttilio Rao #include <ctype.h> 37*de112993SJohn Baldwin #include <err.h> 38b4cc0838SAndrew Gallatin #include <paths.h> 391b4822a4SAttilio Rao #include <stdio.h> 401b4822a4SAttilio Rao #include <stdlib.h> 411b4822a4SAttilio Rao #include <string.h> 421b4822a4SAttilio Rao 431b4822a4SAttilio Rao #include <unistd.h> 441b4822a4SAttilio Rao 4504abf5f1SJohn-Mark Gurney /* NB: Make sure FNBUFF is as large as LNBUFF, otherwise it could overflow */ 46caaeeed4SGeorge V. Neville-Neil #define FNBUFF 512 47caaeeed4SGeorge V. Neville-Neil #define LNBUFF 512 481b4822a4SAttilio Rao 49b4cc0838SAndrew Gallatin #define TMPNAME "pmcannotate.XXXXXX" 501b4822a4SAttilio Rao 511b4822a4SAttilio Rao #define FATAL(ptr, x ...) do { \ 521b4822a4SAttilio Rao fqueue_deleteall(); \ 531b4822a4SAttilio Rao general_deleteall(); \ 541b4822a4SAttilio Rao if ((ptr) != NULL) \ 551b4822a4SAttilio Rao perror(ptr); \ 561b4822a4SAttilio Rao fprintf(stderr, ##x); \ 571b4822a4SAttilio Rao remove(tbfl); \ 581b4822a4SAttilio Rao remove(tofl); \ 591b4822a4SAttilio Rao exit(EXIT_FAILURE); \ 601b4822a4SAttilio Rao } while (0) 611b4822a4SAttilio Rao 62*de112993SJohn Baldwin #define PERCSAMP(x) ((float)(x) * 100 / totalsamples) 631b4822a4SAttilio Rao 641b4822a4SAttilio Rao struct entry { 651b4822a4SAttilio Rao TAILQ_ENTRY(entry) en_iter; 661b4822a4SAttilio Rao char *en_name; 671b4822a4SAttilio Rao uintptr_t en_pc; 681b4822a4SAttilio Rao uintptr_t en_ostart; 691b4822a4SAttilio Rao uintptr_t en_oend; 701b4822a4SAttilio Rao u_int en_nsamples; 711b4822a4SAttilio Rao }; 721b4822a4SAttilio Rao 731b4822a4SAttilio Rao struct aggent { 741b4822a4SAttilio Rao TAILQ_ENTRY(aggent) ag_fiter; 751b4822a4SAttilio Rao long ag_offset; 761b4822a4SAttilio Rao uintptr_t ag_ostart; 771b4822a4SAttilio Rao uintptr_t ag_oend; 781b4822a4SAttilio Rao char *ag_name; 791b4822a4SAttilio Rao u_int ag_nsamples; 801b4822a4SAttilio Rao }; 811b4822a4SAttilio Rao 821b4822a4SAttilio Rao static struct aggent *agg_create(const char *name, u_int nsamples, 831b4822a4SAttilio Rao uintptr_t start, uintptr_t end); 841b4822a4SAttilio Rao static void agg_destroy(struct aggent *agg) __unused; 851b4822a4SAttilio Rao static void asmparse(FILE *fp); 861b4822a4SAttilio Rao static int cparse(FILE *fp); 871b4822a4SAttilio Rao static void entry_acqref(struct entry *entry); 881b4822a4SAttilio Rao static struct entry *entry_create(const char *name, uintptr_t pc, 891b4822a4SAttilio Rao uintptr_t start, uintptr_t end); 901b4822a4SAttilio Rao static void entry_destroy(struct entry *entry) __unused; 911b4822a4SAttilio Rao static void fqueue_compact(float th); 921b4822a4SAttilio Rao static void fqueue_deleteall(void); 931b4822a4SAttilio Rao static struct aggent *fqueue_findent_by_name(const char *name); 941b4822a4SAttilio Rao static int fqueue_getall(const char *bin, char *temp, int asmf); 951b4822a4SAttilio Rao static int fqueue_insertent(struct entry *entry); 961b4822a4SAttilio Rao static int fqueue_insertgen(void); 971b4822a4SAttilio Rao static void general_deleteall(void); 981b4822a4SAttilio Rao static struct entry *general_findent(uintptr_t pc); 991b4822a4SAttilio Rao static void general_insertent(struct entry *entry); 1001b4822a4SAttilio Rao static void general_printasm(FILE *fp, struct aggent *agg); 1011b4822a4SAttilio Rao static int general_printc(FILE *fp, struct aggent *agg); 1021b4822a4SAttilio Rao static int printblock(FILE *fp, struct aggent *agg); 1031b4822a4SAttilio Rao static void usage(const char *progname) __dead2; 1041b4822a4SAttilio Rao 1051b4822a4SAttilio Rao static TAILQ_HEAD(, entry) mainlst = TAILQ_HEAD_INITIALIZER(mainlst); 1061b4822a4SAttilio Rao static TAILQ_HEAD(, aggent) fqueue = TAILQ_HEAD_INITIALIZER(fqueue); 1071b4822a4SAttilio Rao 1081b4822a4SAttilio Rao /* 1091b4822a4SAttilio Rao * Use a float value in order to automatically promote operations 1101b4822a4SAttilio Rao * to return a float value rather than use casts. 1111b4822a4SAttilio Rao */ 112*de112993SJohn Baldwin static u_int totalsamples; 113*de112993SJohn Baldwin 114*de112993SJohn Baldwin static enum { RAW, BLOCK_PERCENT, GLOBAL_PERCENT } print_mode; 1151b4822a4SAttilio Rao 1161b4822a4SAttilio Rao /* 1171b4822a4SAttilio Rao * Identifies a string cointaining objdump's assembly printout. 1181b4822a4SAttilio Rao */ 1191b4822a4SAttilio Rao static inline int 1201b4822a4SAttilio Rao isasminline(const char *str) 1211b4822a4SAttilio Rao { 1221b4822a4SAttilio Rao void *ptr; 1231b4822a4SAttilio Rao int nbytes; 1241b4822a4SAttilio Rao 1251b4822a4SAttilio Rao if (sscanf(str, " %p%n", &ptr, &nbytes) != 1) 1261b4822a4SAttilio Rao return (0); 1271b4822a4SAttilio Rao if (str[nbytes] != ':' || isspace(str[nbytes + 1]) == 0) 1281b4822a4SAttilio Rao return (0); 1291b4822a4SAttilio Rao return (1); 1301b4822a4SAttilio Rao } 1311b4822a4SAttilio Rao 1321b4822a4SAttilio Rao /* 1331b4822a4SAttilio Rao * Identifies a string containing objdump's assembly printout 1341b4822a4SAttilio Rao * for a new function. 1351b4822a4SAttilio Rao */ 1361b4822a4SAttilio Rao static inline int 1371b4822a4SAttilio Rao newfunction(const char *str) 1381b4822a4SAttilio Rao { 1391b4822a4SAttilio Rao char fname[FNBUFF]; 1401b4822a4SAttilio Rao void *ptr; 1411b4822a4SAttilio Rao int nbytes; 1421b4822a4SAttilio Rao 1431b4822a4SAttilio Rao if (isspace(str[0])) 1441b4822a4SAttilio Rao return (0); 1451b4822a4SAttilio Rao if (sscanf(str, "%p <%[^>:]>:%n", &ptr, fname, &nbytes) != 2) 1461b4822a4SAttilio Rao return (0); 1471b4822a4SAttilio Rao return (nbytes); 1481b4822a4SAttilio Rao } 1491b4822a4SAttilio Rao 1501b4822a4SAttilio Rao /* 1511b4822a4SAttilio Rao * Create a new first-level aggregation object for a specified 1521b4822a4SAttilio Rao * function. 1531b4822a4SAttilio Rao */ 1541b4822a4SAttilio Rao static struct aggent * 1551b4822a4SAttilio Rao agg_create(const char *name, u_int nsamples, uintptr_t start, uintptr_t end) 1561b4822a4SAttilio Rao { 1571b4822a4SAttilio Rao struct aggent *agg; 1581b4822a4SAttilio Rao 1591b4822a4SAttilio Rao agg = calloc(1, sizeof(struct aggent)); 1601b4822a4SAttilio Rao if (agg == NULL) 1611b4822a4SAttilio Rao return (NULL); 1621b4822a4SAttilio Rao agg->ag_name = strdup(name); 1631b4822a4SAttilio Rao if (agg->ag_name == NULL) { 1641b4822a4SAttilio Rao free(agg); 1651b4822a4SAttilio Rao return (NULL); 1661b4822a4SAttilio Rao } 1671b4822a4SAttilio Rao agg->ag_nsamples = nsamples; 1681b4822a4SAttilio Rao agg->ag_ostart = start; 1691b4822a4SAttilio Rao agg->ag_oend = end; 1701b4822a4SAttilio Rao return (agg); 1711b4822a4SAttilio Rao } 1721b4822a4SAttilio Rao 1731b4822a4SAttilio Rao /* 1741b4822a4SAttilio Rao * Destroy a first-level aggregation object for a specified 1751b4822a4SAttilio Rao * function. 1761b4822a4SAttilio Rao */ 1771b4822a4SAttilio Rao static void 1781b4822a4SAttilio Rao agg_destroy(struct aggent *agg) 1791b4822a4SAttilio Rao { 1801b4822a4SAttilio Rao 1811b4822a4SAttilio Rao free(agg->ag_name); 1821b4822a4SAttilio Rao free(agg); 1831b4822a4SAttilio Rao } 1841b4822a4SAttilio Rao 1851b4822a4SAttilio Rao /* 1861b4822a4SAttilio Rao * Analyze the "objdump -d" output, locate functions and start 1871b4822a4SAttilio Rao * printing out the assembly functions content. 1881b4822a4SAttilio Rao * We do not use newfunction() because we actually need the 1891b4822a4SAttilio Rao * function name in available form, but the heurstic used is 1901b4822a4SAttilio Rao * the same. 1911b4822a4SAttilio Rao */ 1921b4822a4SAttilio Rao static void 1931b4822a4SAttilio Rao asmparse(FILE *fp) 1941b4822a4SAttilio Rao { 1951b4822a4SAttilio Rao char buffer[LNBUFF], fname[FNBUFF]; 1961b4822a4SAttilio Rao struct aggent *agg; 1971b4822a4SAttilio Rao void *ptr; 1981b4822a4SAttilio Rao 1991b4822a4SAttilio Rao while (fgets(buffer, LNBUFF, fp) != NULL) { 2001b4822a4SAttilio Rao if (isspace(buffer[0])) 2011b4822a4SAttilio Rao continue; 2021b4822a4SAttilio Rao if (sscanf(buffer, "%p <%[^>:]>:", &ptr, fname) != 2) 2031b4822a4SAttilio Rao continue; 2041b4822a4SAttilio Rao agg = fqueue_findent_by_name(fname); 2051b4822a4SAttilio Rao if (agg == NULL) 2061b4822a4SAttilio Rao continue; 2071b4822a4SAttilio Rao agg->ag_offset = ftell(fp); 2081b4822a4SAttilio Rao } 2091b4822a4SAttilio Rao 2101b4822a4SAttilio Rao TAILQ_FOREACH(agg, &fqueue, ag_fiter) { 2111b4822a4SAttilio Rao if (fseek(fp, agg->ag_offset, SEEK_SET) == -1) 2121b4822a4SAttilio Rao return; 2131b4822a4SAttilio Rao printf("Profile trace for function: %s() [%.2f%%]\n", 2141b4822a4SAttilio Rao agg->ag_name, PERCSAMP(agg->ag_nsamples)); 2151b4822a4SAttilio Rao general_printasm(fp, agg); 2161b4822a4SAttilio Rao printf("\n"); 2171b4822a4SAttilio Rao } 2181b4822a4SAttilio Rao } 2191b4822a4SAttilio Rao 2201b4822a4SAttilio Rao /* 2211b4822a4SAttilio Rao * Analyze the "objdump -S" output, locate functions and start 2221b4822a4SAttilio Rao * printing out the C functions content. 2231b4822a4SAttilio Rao * We do not use newfunction() because we actually need the 2241b4822a4SAttilio Rao * function name in available form, but the heurstic used is 2251b4822a4SAttilio Rao * the same. 2261b4822a4SAttilio Rao * In order to maintain the printout sorted, on the first pass it 2271b4822a4SAttilio Rao * simply stores the file offsets in order to fastly moved later 2281b4822a4SAttilio Rao * (when the file is hot-cached also) when the real printout will 2291b4822a4SAttilio Rao * happen. 2301b4822a4SAttilio Rao */ 2311b4822a4SAttilio Rao static int 2321b4822a4SAttilio Rao cparse(FILE *fp) 2331b4822a4SAttilio Rao { 2341b4822a4SAttilio Rao char buffer[LNBUFF], fname[FNBUFF]; 2351b4822a4SAttilio Rao struct aggent *agg; 2361b4822a4SAttilio Rao void *ptr; 2371b4822a4SAttilio Rao 2381b4822a4SAttilio Rao while (fgets(buffer, LNBUFF, fp) != NULL) { 2391b4822a4SAttilio Rao if (isspace(buffer[0])) 2401b4822a4SAttilio Rao continue; 2411b4822a4SAttilio Rao if (sscanf(buffer, "%p <%[^>:]>:", &ptr, fname) != 2) 2421b4822a4SAttilio Rao continue; 2431b4822a4SAttilio Rao agg = fqueue_findent_by_name(fname); 2441b4822a4SAttilio Rao if (agg == NULL) 2451b4822a4SAttilio Rao continue; 2461b4822a4SAttilio Rao agg->ag_offset = ftell(fp); 2471b4822a4SAttilio Rao } 2481b4822a4SAttilio Rao 2491b4822a4SAttilio Rao TAILQ_FOREACH(agg, &fqueue, ag_fiter) { 2501b4822a4SAttilio Rao if (fseek(fp, agg->ag_offset, SEEK_SET) == -1) 2511b4822a4SAttilio Rao return (-1); 2521b4822a4SAttilio Rao printf("Profile trace for function: %s() [%.2f%%]\n", 2531b4822a4SAttilio Rao agg->ag_name, PERCSAMP(agg->ag_nsamples)); 2541b4822a4SAttilio Rao if (general_printc(fp, agg) == -1) 2551b4822a4SAttilio Rao return (-1); 2561b4822a4SAttilio Rao printf("\n"); 2571b4822a4SAttilio Rao } 2581b4822a4SAttilio Rao return (0); 2591b4822a4SAttilio Rao } 2601b4822a4SAttilio Rao 2611b4822a4SAttilio Rao /* 2621b4822a4SAttilio Rao * Bump the number of samples for any raw entry. 2631b4822a4SAttilio Rao */ 2641b4822a4SAttilio Rao static void 2651b4822a4SAttilio Rao entry_acqref(struct entry *entry) 2661b4822a4SAttilio Rao { 2671b4822a4SAttilio Rao 2681b4822a4SAttilio Rao entry->en_nsamples++; 2691b4822a4SAttilio Rao } 2701b4822a4SAttilio Rao 2711b4822a4SAttilio Rao /* 2721b4822a4SAttilio Rao * Create a new raw entry object for a specified function. 2731b4822a4SAttilio Rao */ 2741b4822a4SAttilio Rao static struct entry * 2751b4822a4SAttilio Rao entry_create(const char *name, uintptr_t pc, uintptr_t start, uintptr_t end) 2761b4822a4SAttilio Rao { 2771b4822a4SAttilio Rao struct entry *obj; 2781b4822a4SAttilio Rao 2791b4822a4SAttilio Rao obj = calloc(1, sizeof(struct entry)); 2801b4822a4SAttilio Rao if (obj == NULL) 2811b4822a4SAttilio Rao return (NULL); 2821b4822a4SAttilio Rao obj->en_name = strdup(name); 2831b4822a4SAttilio Rao if (obj->en_name == NULL) { 2841b4822a4SAttilio Rao free(obj); 2851b4822a4SAttilio Rao return (NULL); 2861b4822a4SAttilio Rao } 2871b4822a4SAttilio Rao obj->en_pc = pc; 2881b4822a4SAttilio Rao obj->en_ostart = start; 2891b4822a4SAttilio Rao obj->en_oend = end; 2901b4822a4SAttilio Rao obj->en_nsamples = 1; 2911b4822a4SAttilio Rao return (obj); 2921b4822a4SAttilio Rao } 2931b4822a4SAttilio Rao 2941b4822a4SAttilio Rao /* 2951b4822a4SAttilio Rao * Destroy a raw entry object for a specified function. 2961b4822a4SAttilio Rao */ 2971b4822a4SAttilio Rao static void 2981b4822a4SAttilio Rao entry_destroy(struct entry *entry) 2991b4822a4SAttilio Rao { 3001b4822a4SAttilio Rao 3011b4822a4SAttilio Rao free(entry->en_name); 3021b4822a4SAttilio Rao free(entry); 3031b4822a4SAttilio Rao } 3041b4822a4SAttilio Rao 3051b4822a4SAttilio Rao /* 3061b4822a4SAttilio Rao * Specify a lower bound in percentage and drop from the 3071b4822a4SAttilio Rao * first-level aggregation queue all the objects with a 3081b4822a4SAttilio Rao * smaller impact. 3091b4822a4SAttilio Rao */ 3101b4822a4SAttilio Rao static void 3111b4822a4SAttilio Rao fqueue_compact(float th) 3121b4822a4SAttilio Rao { 3131b4822a4SAttilio Rao u_int thi; 3141b4822a4SAttilio Rao struct aggent *agg, *tmpagg; 3151b4822a4SAttilio Rao 3161b4822a4SAttilio Rao if (totalsamples == 0) 3171b4822a4SAttilio Rao return; 3181b4822a4SAttilio Rao 3191b4822a4SAttilio Rao /* Revert the percentage calculation. */ 3201b4822a4SAttilio Rao thi = th * totalsamples / 100; 3211b4822a4SAttilio Rao TAILQ_FOREACH_SAFE(agg, &fqueue, ag_fiter, tmpagg) 3221b4822a4SAttilio Rao if (agg->ag_nsamples < thi) 3231b4822a4SAttilio Rao TAILQ_REMOVE(&fqueue, agg, ag_fiter); 3241b4822a4SAttilio Rao } 3251b4822a4SAttilio Rao 3261b4822a4SAttilio Rao /* 3271b4822a4SAttilio Rao * Flush the first-level aggregates queue. 3281b4822a4SAttilio Rao */ 3291b4822a4SAttilio Rao static void 33010bc3a7fSEd Schouten fqueue_deleteall(void) 3311b4822a4SAttilio Rao { 3321b4822a4SAttilio Rao struct aggent *agg; 3331b4822a4SAttilio Rao 3341b4822a4SAttilio Rao while (TAILQ_EMPTY(&fqueue) == 0) { 3351b4822a4SAttilio Rao agg = TAILQ_FIRST(&fqueue); 3361b4822a4SAttilio Rao TAILQ_REMOVE(&fqueue, agg, ag_fiter); 3371b4822a4SAttilio Rao } 3381b4822a4SAttilio Rao } 3391b4822a4SAttilio Rao 3401b4822a4SAttilio Rao /* 3411b4822a4SAttilio Rao * Insert a raw entry into the aggregations queue. 3421b4822a4SAttilio Rao * If the respective first-level aggregation object 3431b4822a4SAttilio Rao * does not exist create it and maintain it sorted 3441b4822a4SAttilio Rao * in respect of the number of samples. 3451b4822a4SAttilio Rao */ 3461b4822a4SAttilio Rao static int 3471b4822a4SAttilio Rao fqueue_insertent(struct entry *entry) 3481b4822a4SAttilio Rao { 3491b4822a4SAttilio Rao struct aggent *obj, *tmp; 3501b4822a4SAttilio Rao int found; 3511b4822a4SAttilio Rao 3521b4822a4SAttilio Rao found = 0; 3531b4822a4SAttilio Rao TAILQ_FOREACH(obj, &fqueue, ag_fiter) 3541b4822a4SAttilio Rao if (!strcmp(obj->ag_name, entry->en_name)) { 3551b4822a4SAttilio Rao found = 1; 3561b4822a4SAttilio Rao obj->ag_nsamples += entry->en_nsamples; 3571b4822a4SAttilio Rao break; 3581b4822a4SAttilio Rao } 3591b4822a4SAttilio Rao 3601b4822a4SAttilio Rao /* 36154ac64abSBenedict Reuschling * If the first-level aggregation object already exists, 3621b4822a4SAttilio Rao * just aggregate the samples and, if needed, resort 3631b4822a4SAttilio Rao * it. 3641b4822a4SAttilio Rao */ 3651b4822a4SAttilio Rao if (found) { 3661b4822a4SAttilio Rao TAILQ_REMOVE(&fqueue, obj, ag_fiter); 3671b4822a4SAttilio Rao found = 0; 3681b4822a4SAttilio Rao TAILQ_FOREACH(tmp, &fqueue, ag_fiter) 3691b4822a4SAttilio Rao if (obj->ag_nsamples > tmp->ag_nsamples) { 3701b4822a4SAttilio Rao found = 1; 3711b4822a4SAttilio Rao break; 3721b4822a4SAttilio Rao } 3731b4822a4SAttilio Rao if (found) 3741b4822a4SAttilio Rao TAILQ_INSERT_BEFORE(tmp, obj, ag_fiter); 3751b4822a4SAttilio Rao else 3761b4822a4SAttilio Rao TAILQ_INSERT_TAIL(&fqueue, obj, ag_fiter); 3771b4822a4SAttilio Rao return (0); 3781b4822a4SAttilio Rao } 3791b4822a4SAttilio Rao 3801b4822a4SAttilio Rao /* 3811b4822a4SAttilio Rao * If the first-level aggregation object does not 3821b4822a4SAttilio Rao * exist, create it and put in the sorted queue. 3831b4822a4SAttilio Rao * If this is the first object, we need to set the 3841b4822a4SAttilio Rao * head of the queue. 3851b4822a4SAttilio Rao */ 3861b4822a4SAttilio Rao obj = agg_create(entry->en_name, entry->en_nsamples, entry->en_ostart, 3871b4822a4SAttilio Rao entry->en_oend); 3881b4822a4SAttilio Rao if (obj == NULL) 3891b4822a4SAttilio Rao return (-1); 3901b4822a4SAttilio Rao if (TAILQ_EMPTY(&fqueue) != 0) { 3911b4822a4SAttilio Rao TAILQ_INSERT_HEAD(&fqueue, obj, ag_fiter); 3921b4822a4SAttilio Rao return (0); 3931b4822a4SAttilio Rao } 3941b4822a4SAttilio Rao TAILQ_FOREACH(tmp, &fqueue, ag_fiter) 3951b4822a4SAttilio Rao if (obj->ag_nsamples > tmp->ag_nsamples) { 3961b4822a4SAttilio Rao found = 1; 3971b4822a4SAttilio Rao break; 3981b4822a4SAttilio Rao } 3991b4822a4SAttilio Rao if (found) 4001b4822a4SAttilio Rao TAILQ_INSERT_BEFORE(tmp, obj, ag_fiter); 4011b4822a4SAttilio Rao else 4021b4822a4SAttilio Rao TAILQ_INSERT_TAIL(&fqueue, obj, ag_fiter); 4031b4822a4SAttilio Rao return (0); 4041b4822a4SAttilio Rao } 4051b4822a4SAttilio Rao 4061b4822a4SAttilio Rao /* 4071b4822a4SAttilio Rao * Lookup a first-level aggregation object by name. 4081b4822a4SAttilio Rao */ 4091b4822a4SAttilio Rao static struct aggent * 4101b4822a4SAttilio Rao fqueue_findent_by_name(const char *name) 4111b4822a4SAttilio Rao { 4121b4822a4SAttilio Rao struct aggent *obj; 4131b4822a4SAttilio Rao 4141b4822a4SAttilio Rao TAILQ_FOREACH(obj, &fqueue, ag_fiter) 4151b4822a4SAttilio Rao if (!strcmp(obj->ag_name, name)) 4161b4822a4SAttilio Rao return (obj); 4171b4822a4SAttilio Rao return (NULL); 4181b4822a4SAttilio Rao } 4191b4822a4SAttilio Rao 4201b4822a4SAttilio Rao /* 4211b4822a4SAttilio Rao * Return the number of object in the first-level aggregations queue. 4221b4822a4SAttilio Rao */ 4231b4822a4SAttilio Rao static int 4241b4822a4SAttilio Rao fqueue_getall(const char *bin, char *temp, int asmf) 4251b4822a4SAttilio Rao { 4261b4822a4SAttilio Rao char tmpf[MAXPATHLEN * 2 + 50]; 4271b4822a4SAttilio Rao struct aggent *agg; 4281b4822a4SAttilio Rao uintptr_t start, end; 4291b4822a4SAttilio Rao 4301b4822a4SAttilio Rao if (mkstemp(temp) == -1) 4311b4822a4SAttilio Rao return (-1); 4321b4822a4SAttilio Rao TAILQ_FOREACH(agg, &fqueue, ag_fiter) { 4331b4822a4SAttilio Rao bzero(tmpf, sizeof(tmpf)); 4341b4822a4SAttilio Rao start = agg->ag_ostart; 4351b4822a4SAttilio Rao end = agg->ag_oend; 4361b4822a4SAttilio Rao 4371b4822a4SAttilio Rao if (asmf) 4381b4822a4SAttilio Rao snprintf(tmpf, sizeof(tmpf), 4391b4822a4SAttilio Rao "objdump --start-address=%p " 4401b4822a4SAttilio Rao "--stop-address=%p -d %s >> %s", (void *)start, 4411b4822a4SAttilio Rao (void *)end, bin, temp); 4421b4822a4SAttilio Rao else 4431b4822a4SAttilio Rao snprintf(tmpf, sizeof(tmpf), 4441b4822a4SAttilio Rao "objdump --start-address=%p " 4451b4822a4SAttilio Rao "--stop-address=%p -S %s >> %s", (void *)start, 4461b4822a4SAttilio Rao (void *)end, bin, temp); 4471b4822a4SAttilio Rao if (system(tmpf) != 0) 4481b4822a4SAttilio Rao return (-1); 4491b4822a4SAttilio Rao } 4501b4822a4SAttilio Rao return (0); 4511b4822a4SAttilio Rao } 4521b4822a4SAttilio Rao 4531b4822a4SAttilio Rao /* 4541b4822a4SAttilio Rao * Insert all the raw entries present in the general queue 4551b4822a4SAttilio Rao * into the first-level aggregations queue. 4561b4822a4SAttilio Rao */ 4571b4822a4SAttilio Rao static int 4581b4822a4SAttilio Rao fqueue_insertgen(void) 4591b4822a4SAttilio Rao { 4601b4822a4SAttilio Rao struct entry *obj; 4611b4822a4SAttilio Rao 4621b4822a4SAttilio Rao TAILQ_FOREACH(obj, &mainlst, en_iter) 4631b4822a4SAttilio Rao if (fqueue_insertent(obj) == -1) 4641b4822a4SAttilio Rao return (-1); 4651b4822a4SAttilio Rao return (0); 4661b4822a4SAttilio Rao } 4671b4822a4SAttilio Rao 4681b4822a4SAttilio Rao /* 4691b4822a4SAttilio Rao * Flush the raw entries general queue. 4701b4822a4SAttilio Rao */ 4711b4822a4SAttilio Rao static void 47210bc3a7fSEd Schouten general_deleteall(void) 4731b4822a4SAttilio Rao { 4741b4822a4SAttilio Rao struct entry *obj; 4751b4822a4SAttilio Rao 4761b4822a4SAttilio Rao while (TAILQ_EMPTY(&mainlst) == 0) { 4771b4822a4SAttilio Rao obj = TAILQ_FIRST(&mainlst); 4781b4822a4SAttilio Rao TAILQ_REMOVE(&mainlst, obj, en_iter); 4791b4822a4SAttilio Rao } 4801b4822a4SAttilio Rao } 4811b4822a4SAttilio Rao 4821b4822a4SAttilio Rao /* 4831b4822a4SAttilio Rao * Lookup a raw entry by the PC. 4841b4822a4SAttilio Rao */ 4851b4822a4SAttilio Rao static struct entry * 4861b4822a4SAttilio Rao general_findent(uintptr_t pc) 4871b4822a4SAttilio Rao { 4881b4822a4SAttilio Rao struct entry *obj; 4891b4822a4SAttilio Rao 4901b4822a4SAttilio Rao TAILQ_FOREACH(obj, &mainlst, en_iter) 4911b4822a4SAttilio Rao if (obj->en_pc == pc) 4921b4822a4SAttilio Rao return (obj); 4931b4822a4SAttilio Rao return (NULL); 4941b4822a4SAttilio Rao } 4951b4822a4SAttilio Rao 4961b4822a4SAttilio Rao /* 4971b4822a4SAttilio Rao * Insert a new raw entry in the general queue. 4981b4822a4SAttilio Rao */ 4991b4822a4SAttilio Rao static void 5001b4822a4SAttilio Rao general_insertent(struct entry *entry) 5011b4822a4SAttilio Rao { 5021b4822a4SAttilio Rao 5031b4822a4SAttilio Rao TAILQ_INSERT_TAIL(&mainlst, entry, en_iter); 5041b4822a4SAttilio Rao } 5051b4822a4SAttilio Rao 5061b4822a4SAttilio Rao /* 507*de112993SJohn Baldwin * Return a string either holding a percentage or the raw count value. 508*de112993SJohn Baldwin */ 509*de112993SJohn Baldwin static const char * 510*de112993SJohn Baldwin print_count(u_int nsamples, u_int totsamples) 511*de112993SJohn Baldwin { 512*de112993SJohn Baldwin static char buf[16]; 513*de112993SJohn Baldwin 514*de112993SJohn Baldwin switch (print_mode) { 515*de112993SJohn Baldwin case RAW: 516*de112993SJohn Baldwin snprintf(buf, sizeof(buf), "%u", nsamples); 517*de112993SJohn Baldwin break; 518*de112993SJohn Baldwin case BLOCK_PERCENT: 519*de112993SJohn Baldwin snprintf(buf, sizeof(buf), "%.2f%%", (float)nsamples * 100 / 520*de112993SJohn Baldwin totsamples); 521*de112993SJohn Baldwin break; 522*de112993SJohn Baldwin case GLOBAL_PERCENT: 523*de112993SJohn Baldwin snprintf(buf, sizeof(buf), "%.2f%%", (float)nsamples * 100 / 524*de112993SJohn Baldwin totalsamples); 525*de112993SJohn Baldwin break; 526*de112993SJohn Baldwin } 527*de112993SJohn Baldwin return (buf); 528*de112993SJohn Baldwin } 529*de112993SJohn Baldwin 530*de112993SJohn Baldwin /* 5311b4822a4SAttilio Rao * Printout the body of an "objdump -d" assembly function. 5321b4822a4SAttilio Rao * It does simply stops when a new function is encountered, 5331b4822a4SAttilio Rao * bringing back the file position in order to not mess up 5341b4822a4SAttilio Rao * subsequent analysis. 5351b4822a4SAttilio Rao * C lines and others not recognized are simply skipped. 5361b4822a4SAttilio Rao */ 5371b4822a4SAttilio Rao static void 5381b4822a4SAttilio Rao general_printasm(FILE *fp, struct aggent *agg) 5391b4822a4SAttilio Rao { 5401b4822a4SAttilio Rao char buffer[LNBUFF]; 5411b4822a4SAttilio Rao struct entry *obj; 5421b4822a4SAttilio Rao int nbytes; 5431b4822a4SAttilio Rao void *ptr; 5441b4822a4SAttilio Rao 5451b4822a4SAttilio Rao while (fgets(buffer, LNBUFF, fp) != NULL) { 5461b4822a4SAttilio Rao if ((nbytes = newfunction(buffer)) != 0) { 5471b4822a4SAttilio Rao fseek(fp, nbytes * -1, SEEK_CUR); 5481b4822a4SAttilio Rao break; 5491b4822a4SAttilio Rao } 5501b4822a4SAttilio Rao if (!isasminline(buffer)) 5511b4822a4SAttilio Rao continue; 5521b4822a4SAttilio Rao if (sscanf(buffer, " %p:", &ptr) != 1) 5531b4822a4SAttilio Rao continue; 5541b4822a4SAttilio Rao obj = general_findent((uintptr_t)ptr); 5551b4822a4SAttilio Rao if (obj == NULL) 5561b4822a4SAttilio Rao printf("\t| %s", buffer); 5571b4822a4SAttilio Rao else 558*de112993SJohn Baldwin printf("%7s | %s", 559*de112993SJohn Baldwin print_count(obj->en_nsamples, agg->ag_nsamples), 5601b4822a4SAttilio Rao buffer); 5611b4822a4SAttilio Rao } 5621b4822a4SAttilio Rao } 5631b4822a4SAttilio Rao 5641b4822a4SAttilio Rao /* 5651b4822a4SAttilio Rao * Printout the body of an "objdump -S" function. 5661b4822a4SAttilio Rao * It does simply stops when a new function is encountered, 5671b4822a4SAttilio Rao * bringing back the file position in order to not mess up 5681b4822a4SAttilio Rao * subsequent analysis. 5691b4822a4SAttilio Rao * It expect from the starting to the end to find, always, valid blocks 5701b4822a4SAttilio Rao * (see below for an explanation of the "block" concept). 5711b4822a4SAttilio Rao */ 5721b4822a4SAttilio Rao static int 5731b4822a4SAttilio Rao general_printc(FILE *fp, struct aggent *agg) 5741b4822a4SAttilio Rao { 5751b4822a4SAttilio Rao char buffer[LNBUFF]; 5761b4822a4SAttilio Rao 5771b4822a4SAttilio Rao while (fgets(buffer, LNBUFF, fp) != NULL) { 5781b4822a4SAttilio Rao fseek(fp, strlen(buffer) * -1, SEEK_CUR); 5791b4822a4SAttilio Rao if (newfunction(buffer) != 0) 5801b4822a4SAttilio Rao break; 5811b4822a4SAttilio Rao if (printblock(fp, agg) == -1) 5821b4822a4SAttilio Rao return (-1); 5831b4822a4SAttilio Rao } 5841b4822a4SAttilio Rao return (0); 5851b4822a4SAttilio Rao } 5861b4822a4SAttilio Rao 5871b4822a4SAttilio Rao /* 5881b4822a4SAttilio Rao * Printout a single block inside an "objdump -S" function. 5891b4822a4SAttilio Rao * The block is composed of a first part in C and subsequent translation 5901b4822a4SAttilio Rao * in assembly. 5911b4822a4SAttilio Rao * This code also operates a second-level aggregation packing together 5921b4822a4SAttilio Rao * samples relative to PCs into a (lower bottom) block with their 5931b4822a4SAttilio Rao * C (higher half) counterpart. 5941b4822a4SAttilio Rao */ 5951b4822a4SAttilio Rao static int 5961b4822a4SAttilio Rao printblock(FILE *fp, struct aggent *agg) 5971b4822a4SAttilio Rao { 5981b4822a4SAttilio Rao char buffer[LNBUFF]; 5991b4822a4SAttilio Rao long lstart; 6001b4822a4SAttilio Rao struct entry *obj; 6011b4822a4SAttilio Rao u_int tnsamples; 6021b4822a4SAttilio Rao int done, nbytes, sentinel; 6031b4822a4SAttilio Rao void *ptr; 6041b4822a4SAttilio Rao 6051b4822a4SAttilio Rao /* 6061b4822a4SAttilio Rao * We expect the first thing of the block is C code, so simply give 6071b4822a4SAttilio Rao * up if asm line is found. 6081b4822a4SAttilio Rao */ 6091b4822a4SAttilio Rao lstart = ftell(fp); 6101b4822a4SAttilio Rao sentinel = 0; 6111b4822a4SAttilio Rao for (;;) { 6121b4822a4SAttilio Rao if (fgets(buffer, LNBUFF, fp) == NULL) 6131b4822a4SAttilio Rao return (0); 6141b4822a4SAttilio Rao if (isasminline(buffer) != 0) 6151b4822a4SAttilio Rao break; 6161b4822a4SAttilio Rao sentinel = 1; 6171b4822a4SAttilio Rao nbytes = newfunction(buffer); 6181b4822a4SAttilio Rao if (nbytes != 0) { 6191b4822a4SAttilio Rao if (fseek(fp, nbytes * -1, SEEK_CUR) == -1) 6201b4822a4SAttilio Rao return (-1); 6211b4822a4SAttilio Rao return (0); 6221b4822a4SAttilio Rao } 6231b4822a4SAttilio Rao } 6241b4822a4SAttilio Rao 6251b4822a4SAttilio Rao /* 6261b4822a4SAttilio Rao * If the sentinel is not set, it means it did not match any 6271b4822a4SAttilio Rao * "high half" for this code so simply give up. 6281b4822a4SAttilio Rao * Operates the second-level aggregation. 6291b4822a4SAttilio Rao */ 6301b4822a4SAttilio Rao tnsamples = 0; 6311b4822a4SAttilio Rao do { 6321b4822a4SAttilio Rao if (sentinel == 0) 6331b4822a4SAttilio Rao return (-1); 6341b4822a4SAttilio Rao if (sscanf(buffer, " %p:", &ptr) != 1) 6351b4822a4SAttilio Rao return (-1); 6361b4822a4SAttilio Rao obj = general_findent((uintptr_t)ptr); 6371b4822a4SAttilio Rao if (obj != NULL) 6381b4822a4SAttilio Rao tnsamples += obj->en_nsamples; 6391b4822a4SAttilio Rao } while (fgets(buffer, LNBUFF, fp) != NULL && isasminline(buffer) != 0); 6401b4822a4SAttilio Rao 6411b4822a4SAttilio Rao /* Rewind to the start of the block in order to start the printout. */ 6421b4822a4SAttilio Rao if (fseek(fp, lstart, SEEK_SET) == -1) 6431b4822a4SAttilio Rao return (-1); 6441b4822a4SAttilio Rao 6451b4822a4SAttilio Rao /* Again the high half of the block rappresenting the C part. */ 6461b4822a4SAttilio Rao done = 0; 6471b4822a4SAttilio Rao while (fgets(buffer, LNBUFF, fp) != NULL && isasminline(buffer) == 0) { 6481b4822a4SAttilio Rao if (tnsamples == 0 || done != 0) 6491b4822a4SAttilio Rao printf("\t| %s", buffer); 6501b4822a4SAttilio Rao else { 6511b4822a4SAttilio Rao done = 1; 652*de112993SJohn Baldwin printf("%7s | %s", 653*de112993SJohn Baldwin print_count(tnsamples, agg->ag_nsamples), buffer); 6541b4822a4SAttilio Rao } 6551b4822a4SAttilio Rao } 6561b4822a4SAttilio Rao 6571b4822a4SAttilio Rao /* 6581b4822a4SAttilio Rao * Again the low half of the block rappresenting the asm 6591b4822a4SAttilio Rao * translation part. 6601b4822a4SAttilio Rao */ 6611b4822a4SAttilio Rao for (;;) { 6621b4822a4SAttilio Rao if (fgets(buffer, LNBUFF, fp) == NULL) 6631b4822a4SAttilio Rao return (0); 6641b4822a4SAttilio Rao if (isasminline(buffer) == 0) 6651b4822a4SAttilio Rao break; 6661b4822a4SAttilio Rao nbytes = newfunction(buffer); 6671b4822a4SAttilio Rao if (nbytes != 0) { 6681b4822a4SAttilio Rao if (fseek(fp, nbytes * -1, SEEK_CUR) == -1) 6691b4822a4SAttilio Rao return (-1); 6701b4822a4SAttilio Rao return (0); 6711b4822a4SAttilio Rao } 6721b4822a4SAttilio Rao } 6731b4822a4SAttilio Rao if (fseek(fp, strlen(buffer) * -1, SEEK_CUR) == -1) 6741b4822a4SAttilio Rao return (-1); 6751b4822a4SAttilio Rao return (0); 6761b4822a4SAttilio Rao } 6771b4822a4SAttilio Rao 6781b4822a4SAttilio Rao /* 6791b4822a4SAttilio Rao * Helper printout functions. 6801b4822a4SAttilio Rao */ 6811b4822a4SAttilio Rao static void 6821b4822a4SAttilio Rao usage(const char *progname) 6831b4822a4SAttilio Rao { 6841b4822a4SAttilio Rao 6851b4822a4SAttilio Rao fprintf(stderr, 686*de112993SJohn Baldwin "usage: %s [-a] [-h] [-k kfile] [-l lb] [-m mode] pmcraw.out binary\n", 6871b4822a4SAttilio Rao progname); 6881b4822a4SAttilio Rao exit(EXIT_SUCCESS); 6891b4822a4SAttilio Rao } 6901b4822a4SAttilio Rao 6911b4822a4SAttilio Rao int 6921b4822a4SAttilio Rao main(int argc, char *argv[]) 6931b4822a4SAttilio Rao { 694b4cc0838SAndrew Gallatin char buffer[LNBUFF], fname[FNBUFF]; 695b4cc0838SAndrew Gallatin char *tbfl, *tofl, *tmpdir; 6961b4822a4SAttilio Rao char tmpf[MAXPATHLEN * 2 + 50]; 6971b4822a4SAttilio Rao float limit; 6981b4822a4SAttilio Rao char *bin, *exec, *kfile, *ofile; 6991b4822a4SAttilio Rao struct entry *obj; 7001b4822a4SAttilio Rao FILE *gfp, *bfp; 7011b4822a4SAttilio Rao void *ptr, *hstart, *hend; 7021b4822a4SAttilio Rao uintptr_t tmppc, ostart, oend; 7031b4822a4SAttilio Rao int cget, asmsrc; 7041b4822a4SAttilio Rao 7051b4822a4SAttilio Rao exec = argv[0]; 7061b4822a4SAttilio Rao ofile = NULL; 7071b4822a4SAttilio Rao bin = NULL; 7081b4822a4SAttilio Rao kfile = NULL; 7091b4822a4SAttilio Rao asmsrc = 0; 7101b4822a4SAttilio Rao limit = 0.5; 711*de112993SJohn Baldwin print_mode = BLOCK_PERCENT; 712*de112993SJohn Baldwin while ((cget = getopt(argc, argv, "ahl:m:k:")) != -1) 7131b4822a4SAttilio Rao switch(cget) { 7141b4822a4SAttilio Rao case 'a': 7151b4822a4SAttilio Rao asmsrc = 1; 7161b4822a4SAttilio Rao break; 7171b4822a4SAttilio Rao case 'k': 7181b4822a4SAttilio Rao kfile = optarg; 7191b4822a4SAttilio Rao break; 7201b4822a4SAttilio Rao case 'l': 7211b4822a4SAttilio Rao limit = (float)atof(optarg); 7221b4822a4SAttilio Rao break; 723*de112993SJohn Baldwin case 'm': 724*de112993SJohn Baldwin if (strcasecmp(optarg, "raw") == 0) 725*de112993SJohn Baldwin print_mode = RAW; 726*de112993SJohn Baldwin else if (strcasecmp(optarg, "global") == 0) 727*de112993SJohn Baldwin print_mode = GLOBAL_PERCENT; 728*de112993SJohn Baldwin else if (strcasecmp(optarg, "block") == 0) 729*de112993SJohn Baldwin print_mode = BLOCK_PERCENT; 730*de112993SJohn Baldwin else 731*de112993SJohn Baldwin errx(1, "Invalid mode %s", optarg); 732*de112993SJohn Baldwin break; 7331b4822a4SAttilio Rao case 'h': 7341b4822a4SAttilio Rao case '?': 7351b4822a4SAttilio Rao default: 7361b4822a4SAttilio Rao usage(exec); 7371b4822a4SAttilio Rao } 7381b4822a4SAttilio Rao argc -= optind; 7391b4822a4SAttilio Rao argv += optind; 7401b4822a4SAttilio Rao if (argc != 2) 7411b4822a4SAttilio Rao usage(exec); 7421b4822a4SAttilio Rao ofile = argv[0]; 7431b4822a4SAttilio Rao bin = argv[1]; 7441b4822a4SAttilio Rao 7451b4822a4SAttilio Rao if (access(bin, R_OK | F_OK) == -1) 7461b4822a4SAttilio Rao FATAL(exec, "%s: Impossible to locate the binary file\n", 7471b4822a4SAttilio Rao exec); 7481b4822a4SAttilio Rao if (access(ofile, R_OK | F_OK) == -1) 7491b4822a4SAttilio Rao FATAL(exec, "%s: Impossible to locate the pmcstat file\n", 7501b4822a4SAttilio Rao exec); 7511b4822a4SAttilio Rao if (kfile != NULL && access(kfile, R_OK | F_OK) == -1) 7521b4822a4SAttilio Rao FATAL(exec, "%s: Impossible to locate the kernel file\n", 7531b4822a4SAttilio Rao exec); 7541b4822a4SAttilio Rao 7551b4822a4SAttilio Rao bzero(tmpf, sizeof(tmpf)); 756b4cc0838SAndrew Gallatin tmpdir = getenv("TMPDIR"); 757b4cc0838SAndrew Gallatin if (tmpdir == NULL) { 758b4cc0838SAndrew Gallatin asprintf(&tbfl, "%s/%s", _PATH_TMP, TMPNAME); 759b4cc0838SAndrew Gallatin asprintf(&tofl, "%s/%s", _PATH_TMP, TMPNAME); 760b4cc0838SAndrew Gallatin } else { 761b4cc0838SAndrew Gallatin asprintf(&tbfl, "%s/%s", tmpdir, TMPNAME); 762b4cc0838SAndrew Gallatin asprintf(&tofl, "%s/%s", tmpdir, TMPNAME); 763b4cc0838SAndrew Gallatin } 764b4cc0838SAndrew Gallatin if (tofl == NULL || tbfl == NULL) 765b4cc0838SAndrew Gallatin FATAL(exec, "%s: Cannot create tempfile templates\n", 766b4cc0838SAndrew Gallatin exec); 7671b4822a4SAttilio Rao if (mkstemp(tofl) == -1) 7681b4822a4SAttilio Rao FATAL(exec, "%s: Impossible to create the tmp file\n", 7691b4822a4SAttilio Rao exec); 7701b4822a4SAttilio Rao if (kfile != NULL) 7711b4822a4SAttilio Rao snprintf(tmpf, sizeof(tmpf), "pmcstat -k %s -R %s -m %s", 7721b4822a4SAttilio Rao kfile, ofile, tofl); 7731b4822a4SAttilio Rao else 7741b4822a4SAttilio Rao snprintf(tmpf, sizeof(tmpf), "pmcstat -R %s -m %s", ofile, 7751b4822a4SAttilio Rao tofl); 7761b4822a4SAttilio Rao if (system(tmpf) != 0) 7771b4822a4SAttilio Rao FATAL(exec, "%s: Impossible to create the tmp file\n", 7781b4822a4SAttilio Rao exec); 7791b4822a4SAttilio Rao 7801b4822a4SAttilio Rao gfp = fopen(tofl, "r"); 7811b4822a4SAttilio Rao if (gfp == NULL) 7821b4822a4SAttilio Rao FATAL(exec, "%s: Impossible to open the map file\n", 7831b4822a4SAttilio Rao exec); 7841b4822a4SAttilio Rao 7851b4822a4SAttilio Rao /* 7861b4822a4SAttilio Rao * Make the collection of raw entries from a pmcstat mapped file. 7871b4822a4SAttilio Rao * The heuristic here wants strings in the form: 7881b4822a4SAttilio Rao * "addr funcname startfaddr endfaddr". 7891b4822a4SAttilio Rao */ 7901b4822a4SAttilio Rao while (fgets(buffer, LNBUFF, gfp) != NULL) { 7911b4822a4SAttilio Rao if (isspace(buffer[0])) 7921b4822a4SAttilio Rao continue; 7931b4822a4SAttilio Rao if (sscanf(buffer, "%p %s %p %p\n", &ptr, fname, 7941b4822a4SAttilio Rao &hstart, &hend) != 4) 7951b4822a4SAttilio Rao FATAL(NULL, 7961b4822a4SAttilio Rao "%s: Invalid scan of function in the map file\n", 7971b4822a4SAttilio Rao exec); 7981b4822a4SAttilio Rao ostart = (uintptr_t)hstart; 7991b4822a4SAttilio Rao oend = (uintptr_t)hend; 8001b4822a4SAttilio Rao tmppc = (uintptr_t)ptr; 8011b4822a4SAttilio Rao totalsamples++; 8021b4822a4SAttilio Rao obj = general_findent(tmppc); 8031b4822a4SAttilio Rao if (obj != NULL) { 8041b4822a4SAttilio Rao entry_acqref(obj); 8051b4822a4SAttilio Rao continue; 8061b4822a4SAttilio Rao } 8071b4822a4SAttilio Rao obj = entry_create(fname, tmppc, ostart, oend); 8081b4822a4SAttilio Rao if (obj == NULL) 8091b4822a4SAttilio Rao FATAL(exec, 8101b4822a4SAttilio Rao "%s: Impossible to create a new object\n", exec); 8111b4822a4SAttilio Rao general_insertent(obj); 8121b4822a4SAttilio Rao } 8131b4822a4SAttilio Rao if (fclose(gfp) == EOF) 8141b4822a4SAttilio Rao FATAL(exec, "%s: Impossible to close the filedesc\n", 8151b4822a4SAttilio Rao exec); 8161b4822a4SAttilio Rao if (remove(tofl) == -1) 8171b4822a4SAttilio Rao FATAL(exec, "%s: Impossible to remove the tmpfile\n", 8181b4822a4SAttilio Rao exec); 8191b4822a4SAttilio Rao 8201b4822a4SAttilio Rao /* 8211b4822a4SAttilio Rao * Remove the loose end objects and feed the first-level aggregation 8221b4822a4SAttilio Rao * queue. 8231b4822a4SAttilio Rao */ 8241b4822a4SAttilio Rao if (fqueue_insertgen() == -1) 8251b4822a4SAttilio Rao FATAL(exec, "%s: Impossible to generate an analysis\n", 8261b4822a4SAttilio Rao exec); 8271b4822a4SAttilio Rao fqueue_compact(limit); 8281b4822a4SAttilio Rao if (fqueue_getall(bin, tbfl, asmsrc) == -1) 8291b4822a4SAttilio Rao FATAL(exec, "%s: Impossible to create the tmp file\n", 8301b4822a4SAttilio Rao exec); 8311b4822a4SAttilio Rao 8321b4822a4SAttilio Rao bfp = fopen(tbfl, "r"); 8331b4822a4SAttilio Rao if (bfp == NULL) 8341b4822a4SAttilio Rao FATAL(exec, "%s: Impossible to open the binary file\n", 8351b4822a4SAttilio Rao exec); 8361b4822a4SAttilio Rao 8371b4822a4SAttilio Rao if (asmsrc != 0) 8381b4822a4SAttilio Rao asmparse(bfp); 8391b4822a4SAttilio Rao else if (cparse(bfp) == -1) 8401b4822a4SAttilio Rao FATAL(NULL, "%s: Invalid format for the C file\n", exec); 8411b4822a4SAttilio Rao if (fclose(bfp) == EOF) 8421b4822a4SAttilio Rao FATAL(exec, "%s: Impossible to close the filedesc\n", 8431b4822a4SAttilio Rao exec); 8441b4822a4SAttilio Rao if (remove(tbfl) == -1) 8451b4822a4SAttilio Rao FATAL(exec, "%s: Impossible to remove the tmpfile\n", 8461b4822a4SAttilio Rao exec); 8471b4822a4SAttilio Rao return (0); 8481b4822a4SAttilio Rao } 849