1*cb63e24eSchristos /* Copyright (C) 2021-2024 Free Software Foundation, Inc.
24f645668Schristos Contributed by Oracle.
34f645668Schristos
44f645668Schristos This file is part of GNU Binutils.
54f645668Schristos
64f645668Schristos This program is free software; you can redistribute it and/or modify
74f645668Schristos it under the terms of the GNU General Public License as published by
84f645668Schristos the Free Software Foundation; either version 3, or (at your option)
94f645668Schristos any later version.
104f645668Schristos
114f645668Schristos This program is distributed in the hope that it will be useful,
124f645668Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
134f645668Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
144f645668Schristos GNU General Public License for more details.
154f645668Schristos
164f645668Schristos You should have received a copy of the GNU General Public License
174f645668Schristos along with this program; if not, write to the Free Software
184f645668Schristos Foundation, 51 Franklin Street - Fifth Floor, Boston,
194f645668Schristos MA 02110-1301, USA. */
204f645668Schristos
214f645668Schristos /* Hardware counter profiling */
224f645668Schristos #include "hwcdrv.h"
234f645668Schristos #include "hwcfuncs.h"
244f645668Schristos
254f645668Schristos /*---------------------------------------------------------------------------*/
264f645668Schristos /* macros */
274f645668Schristos
284f645668Schristos #define IS_GLOBAL /* Mark global symbols */
294f645668Schristos #define HWCDRV_API static /* Mark functions used by hwcdrv API */
304f645668Schristos
314f645668Schristos /*---------------------------------------------------------------------------*/
324f645668Schristos /* static variables */
334f645668Schristos static uint_t cpcN_npics;
344f645668Schristos static char hwcfuncs_errmsg_buf[1024];
354f645668Schristos static int hwcfuncs_errmsg_enabled = 1;
364f645668Schristos static int hwcfuncs_errmsg_valid;
374f645668Schristos
384f645668Schristos /* --- user counter selections and options */
394f645668Schristos static unsigned hwcdef_cnt; /* number of *active* hardware counters */
404f645668Schristos static Hwcentry hwcdef[MAX_PICS]; /* HWC definitions */
414f645668Schristos static Hwcentry *hwctable[MAX_PICS]; /* HWC definitions */
424f645668Schristos
434f645668Schristos /* --- drivers --- */
444f645668Schristos
454f645668Schristos // default driver
464f645668Schristos
474f645668Schristos HWCDRV_API int
hwcdrv_init(hwcfuncs_abort_fn_t abort_ftn,int * tsd_sz)484f645668Schristos hwcdrv_init (hwcfuncs_abort_fn_t abort_ftn, int* tsd_sz)
494f645668Schristos {
504f645668Schristos return -1;
514f645668Schristos }
524f645668Schristos
534f645668Schristos HWCDRV_API void
hwcdrv_get_info(int * cpuver,const char ** cciname,uint_t * npics,const char ** docref,uint64_t * support)544f645668Schristos hwcdrv_get_info (
554f645668Schristos int * cpuver, const char ** cciname,
564f645668Schristos uint_t * npics, const char ** docref, uint64_t* support) { }
574f645668Schristos
584f645668Schristos HWCDRV_API int
hwcdrv_enable_mt(hwcfuncs_tsd_get_fn_t tsd_ftn)594f645668Schristos hwcdrv_enable_mt (hwcfuncs_tsd_get_fn_t tsd_ftn)
604f645668Schristos {
614f645668Schristos return -1;
624f645668Schristos }
634f645668Schristos
644f645668Schristos HWCDRV_API int
hwcdrv_get_descriptions(hwcf_hwc_cb_t * hwc_find_action,hwcf_attr_cb_t * attr_find_action)654f645668Schristos hwcdrv_get_descriptions (hwcf_hwc_cb_t *hwc_find_action,
664f645668Schristos hwcf_attr_cb_t *attr_find_action)
674f645668Schristos {
684f645668Schristos return 0;
694f645668Schristos }
704f645668Schristos
714f645668Schristos HWCDRV_API int
hwcdrv_assign_regnos(Hwcentry * entries[],unsigned numctrs)724f645668Schristos hwcdrv_assign_regnos (Hwcentry *entries[], unsigned numctrs)
734f645668Schristos {
744f645668Schristos return -1;
754f645668Schristos }
764f645668Schristos
774f645668Schristos HWCDRV_API int
hwcdrv_create_counters(unsigned hwcdef_cnt,Hwcentry * hwcdef)784f645668Schristos hwcdrv_create_counters (unsigned hwcdef_cnt, Hwcentry *hwcdef)
794f645668Schristos {
804f645668Schristos return -1;
814f645668Schristos }
824f645668Schristos
834f645668Schristos HWCDRV_API int
hwcdrv_read_events(hwc_event_t * events,hwc_event_samples_t * samples)844f645668Schristos hwcdrv_read_events (hwc_event_t *events, hwc_event_samples_t*samples)
854f645668Schristos {
864f645668Schristos return -1;
874f645668Schristos }
884f645668Schristos
894f645668Schristos HWCDRV_API int
hwcdrv_start(void)904f645668Schristos hwcdrv_start (void)
914f645668Schristos {
924f645668Schristos return -1;
934f645668Schristos }
944f645668Schristos
954f645668Schristos HWCDRV_API int
hwcdrv_overflow(siginfo_t * si,hwc_event_t * s,hwc_event_t * t)964f645668Schristos hwcdrv_overflow (siginfo_t *si, hwc_event_t *s, hwc_event_t *t)
974f645668Schristos {
984f645668Schristos return 0;
994f645668Schristos }
1004f645668Schristos
1014f645668Schristos HWCDRV_API int
hwcdrv_sighlr_restart(const hwc_event_t * sample)1024f645668Schristos hwcdrv_sighlr_restart (const hwc_event_t *sample)
1034f645668Schristos {
1044f645668Schristos return -1;
1054f645668Schristos }
1064f645668Schristos
1074f645668Schristos HWCDRV_API int
hwcdrv_lwp_suspend(void)1084f645668Schristos hwcdrv_lwp_suspend (void)
1094f645668Schristos {
1104f645668Schristos return -1;
1114f645668Schristos }
1124f645668Schristos
1134f645668Schristos HWCDRV_API int
hwcdrv_lwp_resume(void)1144f645668Schristos hwcdrv_lwp_resume (void)
1154f645668Schristos {
1164f645668Schristos return -1;
1174f645668Schristos }
1184f645668Schristos
1194f645668Schristos HWCDRV_API int
hwcdrv_free_counters(void)1204f645668Schristos hwcdrv_free_counters (void)
1214f645668Schristos {
1224f645668Schristos return 0;
1234f645668Schristos }
1244f645668Schristos
1254f645668Schristos HWCDRV_API int
hwcdrv_lwp_init(void)1264f645668Schristos hwcdrv_lwp_init (void)
1274f645668Schristos {
1284f645668Schristos return 0;
1294f645668Schristos }
1304f645668Schristos
1314f645668Schristos HWCDRV_API void
hwcdrv_lwp_fini(void)1324f645668Schristos hwcdrv_lwp_fini (void) { }
1334f645668Schristos
1344f645668Schristos static hwcdrv_api_t hwcdrv_default = {
1354f645668Schristos hwcdrv_init,
1364f645668Schristos hwcdrv_get_info,
1374f645668Schristos hwcdrv_enable_mt,
1384f645668Schristos hwcdrv_get_descriptions,
1394f645668Schristos hwcdrv_assign_regnos,
1404f645668Schristos hwcdrv_create_counters,
1414f645668Schristos hwcdrv_start,
1424f645668Schristos hwcdrv_overflow,
1434f645668Schristos hwcdrv_read_events,
1444f645668Schristos hwcdrv_sighlr_restart,
1454f645668Schristos hwcdrv_lwp_suspend,
1464f645668Schristos hwcdrv_lwp_resume,
1474f645668Schristos hwcdrv_free_counters,
1484f645668Schristos hwcdrv_lwp_init,
1494f645668Schristos hwcdrv_lwp_fini,
1504f645668Schristos -1 // hwcdrv_init_status
1514f645668Schristos };
1524f645668Schristos
1534f645668Schristos static hwcdrv_api_t *hwcdrv_driver = &hwcdrv_default;
1544f645668Schristos
1554f645668Schristos
1564f645668Schristos /*---------------------------------------------------------------------------*/
1574f645668Schristos /* misc */
1584f645668Schristos
1594f645668Schristos /* print a counter definition (for debugging) */
1604f645668Schristos static void
ctrdefprint(int dbg_lvl,const char * hdr,Hwcentry * phwcdef)1614f645668Schristos ctrdefprint (int dbg_lvl, const char * hdr, Hwcentry*phwcdef)
1624f645668Schristos {
1634f645668Schristos TprintfT (dbg_lvl, "%s: name='%s', int_name='%s',"
1644f645668Schristos " reg_num=%d, timecvt=%d, memop=%d, "
1654f645668Schristos "interval=%d, tag=%u, reg_list=%p\n",
1664f645668Schristos hdr, phwcdef->name, phwcdef->int_name, phwcdef->reg_num,
1674f645668Schristos phwcdef->timecvt, phwcdef->memop, phwcdef->val,
1684f645668Schristos phwcdef->sort_order, phwcdef->reg_list);
1694f645668Schristos }
1704f645668Schristos
1714f645668Schristos /*---------------------------------------------------------------------------*/
1724f645668Schristos /* errmsg buffering */
1734f645668Schristos
1744f645668Schristos /* errmsg buffering is needed only because the most descriptive error
1754f645668Schristos messages from CPC are delivered using a callback mechanism.
1764f645668Schristos hwcfuncs_errmsg_get() should only be used during initialization, and
1774f645668Schristos ideally, only to provide feedback to an end user when his counters can't
1784f645668Schristos be bound to HW.
1794f645668Schristos */
1804f645668Schristos IS_GLOBAL char *
hwcfuncs_errmsg_get(char * buf,size_t bufsize,int enable)1814f645668Schristos hwcfuncs_errmsg_get (char *buf, size_t bufsize, int enable)
1824f645668Schristos {
1834f645668Schristos hwcfuncs_errmsg_enabled = 0;
1844f645668Schristos if (buf && bufsize)
1854f645668Schristos {
1864f645668Schristos if (hwcfuncs_errmsg_valid)
1874f645668Schristos {
1884f645668Schristos strncpy (buf, hwcfuncs_errmsg_buf, bufsize);
1894f645668Schristos buf[bufsize - 1] = 0;
1904f645668Schristos }
1914f645668Schristos else
1924f645668Schristos *buf = 0;
1934f645668Schristos }
1944f645668Schristos hwcfuncs_errmsg_buf[0] = 0;
1954f645668Schristos hwcfuncs_errmsg_valid = 0;
1964f645668Schristos hwcfuncs_errmsg_enabled = enable;
1974f645668Schristos return buf;
1984f645668Schristos }
1994f645668Schristos
2004f645668Schristos /* used by cpc to log an error */
2014f645668Schristos IS_GLOBAL void
hwcfuncs_int_capture_errmsg(const char * fn,int subcode,const char * fmt,va_list ap)2024f645668Schristos hwcfuncs_int_capture_errmsg (const char *fn, int subcode,
2034f645668Schristos const char *fmt, va_list ap)
2044f645668Schristos {
2054f645668Schristos if (hwcfuncs_errmsg_enabled &&
2064f645668Schristos !hwcfuncs_errmsg_valid)
2074f645668Schristos {
2084f645668Schristos vsnprintf (hwcfuncs_errmsg_buf, sizeof (hwcfuncs_errmsg_buf), fmt, ap);
2094f645668Schristos TprintfT (DBG_LT0, "hwcfuncs: cpcN_capture_errmsg(): %s\n",
2104f645668Schristos hwcfuncs_errmsg_buf);
2114f645668Schristos hwcfuncs_errmsg_valid = 1;
2124f645668Schristos }
2134f645668Schristos return;
2144f645668Schristos }
2154f645668Schristos
2164f645668Schristos /* Log an internal error to the CPC error buffer.
2174f645668Schristos * Note: only call this during init functions.
2184f645668Schristos * Note: when most cpc calls fail, they will call cpcN_capture_errmsg()
2194f645668Schristos * directly, so only call logerr() when a non-cpc function fails.
2204f645668Schristos */
2214f645668Schristos IS_GLOBAL void
hwcfuncs_int_logerr(const char * format,...)2224f645668Schristos hwcfuncs_int_logerr (const char *format, ...)
2234f645668Schristos {
2244f645668Schristos va_list va;
2254f645668Schristos va_start (va, format);
2264f645668Schristos hwcfuncs_int_capture_errmsg ("logerr", 0, format, va);
2274f645668Schristos va_end (va);
2284f645668Schristos }
2294f645668Schristos
2304f645668Schristos /* utils to parse counter strings */
2314f645668Schristos static void
clear_hwcdefs()2324f645668Schristos clear_hwcdefs ()
2334f645668Schristos {
2344f645668Schristos for (unsigned idx = 0; idx < MAX_PICS; idx++)
2354f645668Schristos {
2364f645668Schristos static Hwcentry empty;
2374f645668Schristos hwcdef[idx] = empty; // leaks strings and reg_list array
2384f645668Schristos hwcdef[idx].reg_num = REGNO_ANY;
2394f645668Schristos hwcdef[idx].val = -1;
2404f645668Schristos hwcdef[idx].sort_order = -1;
2414f645668Schristos }
2424f645668Schristos }
2434f645668Schristos
2444f645668Schristos /* initialize hwcdef[] based on user's counter definitions */
2454f645668Schristos static int
process_data_descriptor(const char * defstring)2464f645668Schristos process_data_descriptor (const char *defstring)
2474f645668Schristos {
2484f645668Schristos /*
2494f645668Schristos * <defstring> format should be of format
2504f645668Schristos * :%s:%s:0x%x:%d:%lld:%d:%d:0x%x[,%s...repeat for each ctr]
2514f645668Schristos * where the counter fields are:
2524f645668Schristos * :<userName>:<internalCtr>:<register>:<timeoutVal>[:m<min_time>]:<tag>:<timecvt>:<memop>
2534f645668Schristos * See Coll_Ctrl::build_data_desc().
2544f645668Schristos */
2554f645668Schristos int err = 0;
2564f645668Schristos char *ds = NULL;
2574f645668Schristos char *dsp = NULL;
2584f645668Schristos unsigned idx;
2594f645668Schristos
2604f645668Schristos clear_hwcdefs ();
2614f645668Schristos if (!defstring || !strlen (defstring))
262*cb63e24eSchristos return HWCFUNCS_ERROR_HWCARGS;
2634f645668Schristos ds = strdup (defstring);
2644f645668Schristos if (!ds)
265*cb63e24eSchristos return HWCFUNCS_ERROR_HWCINIT;
2664f645668Schristos dsp = ds;
2674f645668Schristos for (idx = 0; idx < MAX_PICS && *dsp; idx++)
2684f645668Schristos {
2694f645668Schristos char *name = NULL;
2704f645668Schristos char *int_name = NULL;
2714f645668Schristos regno_t reg = REGNO_ANY;
2724f645668Schristos ABST_type memop = ABST_NONE;
2734f645668Schristos int interval = 0;
2744f645668Schristos int timecvt = 0;
2754f645668Schristos unsigned sort_order = (unsigned) - 1;
2764f645668Schristos
277*cb63e24eSchristos // Read use_perf_event_type, type, config
278*cb63e24eSchristos hwcdef[idx].use_perf_event_type = (int) strtol (dsp, &dsp, 0);
279*cb63e24eSchristos if (*dsp++ != ':')
280*cb63e24eSchristos {
281*cb63e24eSchristos err = HWCFUNCS_ERROR_HWCARGS;
282*cb63e24eSchristos break;
283*cb63e24eSchristos }
284*cb63e24eSchristos hwcdef[idx].type = (int) strtol (dsp, &dsp, 0);
285*cb63e24eSchristos if (*dsp++ != ':')
286*cb63e24eSchristos {
287*cb63e24eSchristos err = HWCFUNCS_ERROR_HWCARGS;
288*cb63e24eSchristos break;
289*cb63e24eSchristos }
290*cb63e24eSchristos hwcdef[idx].config = strtol (dsp, &dsp, 0);
291*cb63e24eSchristos if (*dsp++ != ':')
292*cb63e24eSchristos {
293*cb63e24eSchristos err = HWCFUNCS_ERROR_HWCARGS;
294*cb63e24eSchristos break;
295*cb63e24eSchristos }
296*cb63e24eSchristos
2974f645668Schristos /* name */
2984f645668Schristos name = dsp;
2994f645668Schristos dsp = strchr (dsp, ':');
3004f645668Schristos if (dsp == NULL)
3014f645668Schristos {
3024f645668Schristos err = HWCFUNCS_ERROR_HWCARGS;
303*cb63e24eSchristos break;
3044f645668Schristos }
3054f645668Schristos *dsp++ = (char) 0;
3064f645668Schristos
3074f645668Schristos /* int_name */
3084f645668Schristos int_name = dsp;
3094f645668Schristos dsp = strchr (dsp, ':');
3104f645668Schristos if (dsp == NULL)
3114f645668Schristos {
3124f645668Schristos err = HWCFUNCS_ERROR_HWCARGS;
313*cb63e24eSchristos break;
3144f645668Schristos }
3154f645668Schristos *dsp++ = (char) 0;
3164f645668Schristos
3174f645668Schristos /* reg_num */
3184f645668Schristos reg = (int) strtol (dsp, &dsp, 0);
3194f645668Schristos if (*dsp++ != ':')
3204f645668Schristos {
3214f645668Schristos err = HWCFUNCS_ERROR_HWCARGS;
322*cb63e24eSchristos break;
3234f645668Schristos }
3244f645668Schristos if (reg < 0 && reg != -1)
3254f645668Schristos {
3264f645668Schristos err = HWCFUNCS_ERROR_HWCARGS;
327*cb63e24eSchristos break;
3284f645668Schristos }
3294f645668Schristos if (reg >= 0)
3304f645668Schristos hwcdef[idx].reg_num = reg;
3314f645668Schristos
3324f645668Schristos /* val */
3334f645668Schristos interval = (int) strtol (dsp, &dsp, 0);
3344f645668Schristos if (*dsp++ != ':')
3354f645668Schristos {
3364f645668Schristos err = HWCFUNCS_ERROR_HWCARGS;
337*cb63e24eSchristos break;
3384f645668Schristos }
3394f645668Schristos if (interval < 0)
3404f645668Schristos {
3414f645668Schristos err = HWCFUNCS_ERROR_HWCARGS;
342*cb63e24eSchristos break;
3434f645668Schristos }
3444f645668Schristos hwcdef[idx].val = interval;
3454f645668Schristos
3464f645668Schristos /* min_time */
3474f645668Schristos if (*dsp == 'm')
3484f645668Schristos {
3494f645668Schristos long long tmp_ll = 0;
3504f645668Schristos dsp++;
3514f645668Schristos tmp_ll = strtoll (dsp, &dsp, 0);
3524f645668Schristos if (*dsp++ != ':')
3534f645668Schristos {
3544f645668Schristos err = HWCFUNCS_ERROR_HWCARGS;
355*cb63e24eSchristos break;
3564f645668Schristos }
3574f645668Schristos if (tmp_ll < 0)
3584f645668Schristos {
3594f645668Schristos err = HWCFUNCS_ERROR_HWCARGS;
360*cb63e24eSchristos break;
3614f645668Schristos }
3624f645668Schristos hwcdef[idx].min_time = tmp_ll;
3634f645668Schristos }
3644f645668Schristos else
3654f645668Schristos hwcdef[idx].min_time = 0;
3664f645668Schristos
3674f645668Schristos /* sort_order */
3684f645668Schristos sort_order = (int) strtoul (dsp, &dsp, 0);
3694f645668Schristos if (*dsp++ != ':')
3704f645668Schristos {
3714f645668Schristos err = HWCFUNCS_ERROR_HWCARGS;
372*cb63e24eSchristos break;
3734f645668Schristos }
3744f645668Schristos hwcdef[idx].sort_order = sort_order;
3754f645668Schristos
3764f645668Schristos /* timecvt */
3774f645668Schristos timecvt = (int) strtol (dsp, &dsp, 0);
3784f645668Schristos if (*dsp++ != ':')
3794f645668Schristos {
3804f645668Schristos err = HWCFUNCS_ERROR_HWCARGS;
381*cb63e24eSchristos break;
3824f645668Schristos }
3834f645668Schristos hwcdef[idx].timecvt = timecvt;
3844f645668Schristos
3854f645668Schristos /* memop */
3864f645668Schristos memop = (ABST_type) strtol (dsp, &dsp, 0);
3874f645668Schristos if (*dsp != 0 && *dsp++ != ',')
3884f645668Schristos {
3894f645668Schristos err = HWCFUNCS_ERROR_HWCARGS;
390*cb63e24eSchristos break;
3914f645668Schristos }
3924f645668Schristos hwcdef[idx].memop = memop;
3934f645668Schristos if (*name)
3944f645668Schristos hwcdef[idx].name = strdup (name);
3954f645668Schristos else
3964f645668Schristos hwcdef[idx].name = strdup (int_name);
3974f645668Schristos if (*int_name)
3984f645668Schristos hwcdef[idx].int_name = strdup (int_name);
3994f645668Schristos else
4004f645668Schristos hwcdef[idx].int_name = strdup (name);
4014f645668Schristos ctrdefprint (DBG_LT1, "hwcfuncs: process_data_descriptor", &hwcdef[idx]);
4024f645668Schristos }
4034f645668Schristos
4044f645668Schristos if (*dsp)
4054f645668Schristos err = HWCFUNCS_ERROR_HWCARGS;
406*cb63e24eSchristos if (err != 0)
4074f645668Schristos logerr (GTXT ("Data descriptor syntax error near `%s'\n"), dsp);
4084f645668Schristos else
409*cb63e24eSchristos hwcdef_cnt = idx;
4104f645668Schristos free (ds);
4114f645668Schristos return err;
4124f645668Schristos }
4134f645668Schristos
4144f645668Schristos /* initialize hwcdef[] based on user's counter definitions */
4154f645668Schristos static int
process_hwcentrylist(const Hwcentry * entries[],unsigned numctrs)4164f645668Schristos process_hwcentrylist (const Hwcentry* entries[], unsigned numctrs)
4174f645668Schristos {
4184f645668Schristos int err = 0;
4194f645668Schristos clear_hwcdefs ();
4204f645668Schristos if (numctrs > cpcN_npics)
4214f645668Schristos {
4224f645668Schristos logerr (GTXT ("More than %d counters were specified\n"), cpcN_npics); /*!*/
4234f645668Schristos return HWCFUNCS_ERROR_HWCARGS;
4244f645668Schristos }
4254f645668Schristos for (unsigned idx = 0; idx < numctrs; idx++)
4264f645668Schristos {
4274f645668Schristos Hwcentry *phwcdef = &hwcdef[idx];
4284f645668Schristos *phwcdef = *entries[idx];
4294f645668Schristos if (phwcdef->name)
4304f645668Schristos phwcdef->name = strdup (phwcdef->name);
4314f645668Schristos else
4324f645668Schristos phwcdef->name = "NULL";
4334f645668Schristos if (phwcdef->int_name)
4344f645668Schristos phwcdef->int_name = strdup (phwcdef->int_name);
4354f645668Schristos else
4364f645668Schristos phwcdef->int_name = "NULL";
4374f645668Schristos if (phwcdef->val < 0)
4384f645668Schristos {
4394f645668Schristos logerr (GTXT ("Negative interval specified for HW counter `%s'\n"), /*!*/
4404f645668Schristos phwcdef->name);
4414f645668Schristos err = HWCFUNCS_ERROR_HWCARGS;
4424f645668Schristos break;
4434f645668Schristos }
4444f645668Schristos ctrdefprint (DBG_LT1, "hwcfuncs: process_hwcentrylist", phwcdef);
4454f645668Schristos }
4464f645668Schristos if (!err)
4474f645668Schristos hwcdef_cnt = numctrs;
4484f645668Schristos return err;
4494f645668Schristos }
4504f645668Schristos
4514f645668Schristos /* see hwcfuncs.h */
4524f645668Schristos IS_GLOBAL void *
hwcfuncs_parse_attrs(const char * countername,hwcfuncs_attr_t attrs[],unsigned max_attrs,uint_t * pnum_attrs,char ** errstring)4534f645668Schristos hwcfuncs_parse_attrs (const char *countername, hwcfuncs_attr_t attrs[],
4544f645668Schristos unsigned max_attrs, uint_t *pnum_attrs, char**errstring)
4554f645668Schristos {
4564f645668Schristos char *head = NULL;
4574f645668Schristos char *tail = NULL;
4584f645668Schristos uint_t nattrs = 0;
4594f645668Schristos char *counter_copy;
4604f645668Schristos int success = 0;
4614f645668Schristos char errbuf[512];
4624f645668Schristos errbuf[0] = 0;
4634f645668Schristos counter_copy = strdup (countername);
4644f645668Schristos
4654f645668Schristos /* advance pointer to first attribute */
4664f645668Schristos tail = strchr (counter_copy, HWCFUNCS_PARSE_ATTR);
4674f645668Schristos if (tail)
4684f645668Schristos *tail = 0;
4694f645668Schristos
4704f645668Schristos /* remove regno and value, if supplied */
4714f645668Schristos {
4724f645668Schristos char *tmp = strchr (counter_copy, HWCFUNCS_PARSE_REGNUM);
4734f645668Schristos if (tmp)
4744f645668Schristos *tmp = 0;
4754f645668Schristos tmp = strchr (counter_copy, HWCFUNCS_PARSE_VALUE);
4764f645668Schristos if (tmp)
4774f645668Schristos *tmp = 0;
4784f645668Schristos }
4794f645668Schristos
4804f645668Schristos while (tail)
4814f645668Schristos {
4824f645668Schristos char *pch;
4834f645668Schristos if (nattrs >= max_attrs)
4844f645668Schristos {
4854f645668Schristos snprintf (errbuf, sizeof (errbuf),
4864f645668Schristos GTXT ("Too many attributes defined in `%s'"),
4874f645668Schristos countername);
4884f645668Schristos goto mycpc2_parse_attrs_end;
4894f645668Schristos }
4904f645668Schristos /* get attribute name */
4914f645668Schristos head = tail + 1;
4924f645668Schristos tail = strchr (head, HWCFUNCS_PARSE_EQUAL);
4934f645668Schristos if (!tail)
4944f645668Schristos {
4954f645668Schristos snprintf (errbuf, sizeof (errbuf),
4964f645668Schristos GTXT ("Missing value for attribute `%s' in `%s'"),
4974f645668Schristos head, countername);
4984f645668Schristos goto mycpc2_parse_attrs_end;
4994f645668Schristos }
5004f645668Schristos *tail = 0; /* null terminate current component */
5014f645668Schristos attrs[nattrs].ca_name = head;
5024f645668Schristos
5034f645668Schristos /* get attribute value */
5044f645668Schristos head = tail + 1;
5054f645668Schristos tail = strchr (head, HWCFUNCS_PARSE_ATTR);
5064f645668Schristos if (tail)
5074f645668Schristos *tail = 0; /* null terminate current component */
5084f645668Schristos attrs[nattrs].ca_val = strtoull (head, &pch, 0);
5094f645668Schristos if (pch == head)
5104f645668Schristos {
5114f645668Schristos snprintf (errbuf, sizeof (errbuf),
5124f645668Schristos GTXT ("Illegal value for attribute `%s' in `%s'"),
5134f645668Schristos attrs[nattrs].ca_name, countername);
5144f645668Schristos goto mycpc2_parse_attrs_end;
5154f645668Schristos }
5164f645668Schristos TprintfT (DBG_LT0, "hwcfuncs: pic_: '%s', attribute[%u]"
5174f645668Schristos " '%s' = 0x%llx\n",
5184f645668Schristos counter_copy, nattrs, attrs[nattrs].ca_name,
5194f645668Schristos (long long unsigned int) attrs[nattrs].ca_val);
5204f645668Schristos
5214f645668Schristos nattrs++;
5224f645668Schristos }
5234f645668Schristos success = 1;
5244f645668Schristos
5254f645668Schristos mycpc2_parse_attrs_end:
5264f645668Schristos *pnum_attrs = nattrs;
5274f645668Schristos if (success)
5284f645668Schristos {
5294f645668Schristos if (errstring)
5304f645668Schristos *errstring = NULL;
5314f645668Schristos }
5324f645668Schristos else
5334f645668Schristos {
5344f645668Schristos if (errstring)
5354f645668Schristos *errstring = strdup (errbuf);
5364f645668Schristos free (counter_copy);
5374f645668Schristos counter_copy = NULL;
5384f645668Schristos }
5394f645668Schristos return counter_copy;
5404f645668Schristos }
5414f645668Schristos
5424f645668Schristos IS_GLOBAL void
hwcfuncs_parse_ctr(const char * counter_def,int * pplus,char ** pnameOnly,char ** pattrs,char ** pregstr,regno_t * pregno)5434f645668Schristos hwcfuncs_parse_ctr (const char *counter_def, int *pplus, char **pnameOnly,
5444f645668Schristos char **pattrs, char **pregstr, regno_t *pregno)
5454f645668Schristos {
5464f645668Schristos char *nameptr, *copy, *slash, *attr_delim;
5474f645668Schristos int plus;
5484f645668Schristos regno_t regno;
5494f645668Schristos nameptr = copy = strdup (counter_def);
5504f645668Schristos
5514f645668Schristos /* plus */
5524f645668Schristos plus = 0;
5534f645668Schristos if (nameptr[0] == HWCFUNCS_PARSE_BACKTRACK)
5544f645668Schristos {
5554f645668Schristos plus = 1;
5564f645668Schristos nameptr++;
5574f645668Schristos }
5584f645668Schristos else if (nameptr[0] == HWCFUNCS_PARSE_BACKTRACK_OFF)
5594f645668Schristos {
5604f645668Schristos plus = -1;
5614f645668Schristos nameptr++;
5624f645668Schristos }
5634f645668Schristos if (pplus)
5644f645668Schristos *pplus = plus;
5654f645668Schristos
5664f645668Schristos /* regno */
5674f645668Schristos regno = REGNO_ANY;
5684f645668Schristos if (pregstr)
5694f645668Schristos *pregstr = NULL;
5704f645668Schristos slash = strchr (nameptr, HWCFUNCS_PARSE_REGNUM);
5714f645668Schristos if (slash != NULL)
5724f645668Schristos {
5734f645668Schristos /* the remaining string should be a number > 0 */
5744f645668Schristos if (pregstr)
5754f645668Schristos *pregstr = strdup (slash);
5764f645668Schristos char *endchar = NULL;
5774f645668Schristos regno = (regno_t) strtol (slash + 1, &endchar, 0);
5784f645668Schristos if (*endchar != 0)
5794f645668Schristos regno = -2;
5804f645668Schristos if (*(slash + 1) == '-')
5814f645668Schristos regno = -2;
5824f645668Schristos /* terminate previous element up to slash */
5834f645668Schristos *slash = 0;
5844f645668Schristos }
5854f645668Schristos if (pregno)
5864f645668Schristos *pregno = regno;
5874f645668Schristos
5884f645668Schristos /* attrs */
5894f645668Schristos if (pattrs)
5904f645668Schristos *pattrs = NULL;
5914f645668Schristos attr_delim = strchr (nameptr, HWCFUNCS_PARSE_ATTR);
5924f645668Schristos if (attr_delim != NULL)
5934f645668Schristos {
5944f645668Schristos if (pattrs)
5954f645668Schristos *pattrs = strdup (attr_delim);
5964f645668Schristos /* terminate previous element up to attr_delim */
5974f645668Schristos *attr_delim++ = 0;
5984f645668Schristos }
5994f645668Schristos if (pnameOnly)
6004f645668Schristos *pnameOnly = strdup (nameptr);
6014f645668Schristos free (copy);
6024f645668Schristos }
6034f645668Schristos
6044f645668Schristos /* create counters */
6054f645668Schristos IS_GLOBAL int
hwcfuncs_bind_descriptor(const char * defstring)6064f645668Schristos hwcfuncs_bind_descriptor (const char *defstring)
6074f645668Schristos {
6084f645668Schristos int err = process_data_descriptor (defstring);
6094f645668Schristos if (err)
6104f645668Schristos {
6114f645668Schristos TprintfT (DBG_LT0, "hwcfuncs: ERROR: hwcfuncs_bind_descriptor failed\n");
6124f645668Schristos return err;
6134f645668Schristos }
6144f645668Schristos err = hwcdrv_driver->hwcdrv_create_counters (hwcdef_cnt, hwcdef);
6154f645668Schristos return err;
6164f645668Schristos }
6174f645668Schristos
6184f645668Schristos /* see hwcfuncs.h */
6194f645668Schristos IS_GLOBAL int
hwcfuncs_bind_hwcentry(const Hwcentry * entries[],unsigned numctrs)6204f645668Schristos hwcfuncs_bind_hwcentry (const Hwcentry* entries[], unsigned numctrs)
6214f645668Schristos {
6224f645668Schristos int err = -1;
6234f645668Schristos err = process_hwcentrylist (entries, numctrs);
6244f645668Schristos if (err)
6254f645668Schristos {
6264f645668Schristos TprintfT (DBG_LT0, "hwcfuncs: ERROR: hwcfuncs_bind_hwcentry\n");
6274f645668Schristos return err;
6284f645668Schristos }
6294f645668Schristos err = hwcdrv_driver->hwcdrv_create_counters (hwcdef_cnt, hwcdef);
6304f645668Schristos return err;
6314f645668Schristos }
6324f645668Schristos
6334f645668Schristos /* see hwcfuncs.h */
6344f645668Schristos IS_GLOBAL Hwcentry **
hwcfuncs_get_ctrs(unsigned * defcnt)6354f645668Schristos hwcfuncs_get_ctrs (unsigned *defcnt)
6364f645668Schristos {
6374f645668Schristos if (defcnt)
6384f645668Schristos *defcnt = hwcdef_cnt;
6394f645668Schristos return hwctable;
6404f645668Schristos }
6414f645668Schristos
6424f645668Schristos /* return 1 if <regno> is in Hwcentry's list */
6434f645668Schristos IS_GLOBAL int
regno_is_valid(const Hwcentry * pctr,regno_t regno)6444f645668Schristos regno_is_valid (const Hwcentry * pctr, regno_t regno)
6454f645668Schristos {
6464f645668Schristos regno_t *reg_list = pctr->reg_list;
6474f645668Schristos if (REG_LIST_IS_EMPTY (reg_list))
6484f645668Schristos return 0;
6494f645668Schristos if (regno == REGNO_ANY) /* wildcard */
6504f645668Schristos return 1;
6514f645668Schristos for (int ii = 0; ii < MAX_PICS; ii++)
6524f645668Schristos {
6534f645668Schristos regno_t tmp = reg_list[ii];
6544f645668Schristos if (REG_LIST_EOL (tmp)) /* end of list */
6554f645668Schristos break;
6564f645668Schristos if (tmp == regno) /* is in list */
6574f645668Schristos return 1;
6584f645668Schristos }
6594f645668Schristos return 0;
6604f645668Schristos }
6614f645668Schristos
6624f645668Schristos /* supplied by hwcdrv_api drivers */
6634f645668Schristos IS_GLOBAL int
hwcfuncs_assign_regnos(Hwcentry * entries[],unsigned numctrs)6644f645668Schristos hwcfuncs_assign_regnos (Hwcentry* entries[],
6654f645668Schristos unsigned numctrs)
6664f645668Schristos {
6674f645668Schristos if (numctrs > cpcN_npics)
6684f645668Schristos {
6694f645668Schristos logerr (GTXT ("More than %d counters were specified\n"), cpcN_npics); /*!*/
6704f645668Schristos return HWCFUNCS_ERROR_HWCARGS;
6714f645668Schristos }
6724f645668Schristos return hwcdrv_driver->hwcdrv_assign_regnos (entries, numctrs);
6734f645668Schristos }
6744f645668Schristos
6754f645668Schristos extern hwcdrv_api_t hwcdrv_pcl_api;
6764f645668Schristos static int hwcdrv_driver_inited = 0;
6774f645668Schristos
6784f645668Schristos hwcdrv_api_t *
get_hwcdrv()6794f645668Schristos get_hwcdrv ()
6804f645668Schristos {
6814f645668Schristos if (hwcdrv_driver_inited)
6824f645668Schristos return hwcdrv_driver;
6834f645668Schristos hwcdrv_driver_inited = 1;
6844f645668Schristos cpcN_npics = 0;
6854f645668Schristos for (int i = 0; i < MAX_PICS; i++)
6864f645668Schristos hwctable[i] = &hwcdef[i];
6874f645668Schristos hwcdrv_driver = &hwcdrv_pcl_api;
6884f645668Schristos hwcdrv_driver->hwcdrv_init_status = hwcdrv_driver->hwcdrv_init (NULL, NULL);
6894f645668Schristos if (hwcdrv_driver->hwcdrv_init_status == 0)
6904f645668Schristos {
6914f645668Schristos hwcdrv_driver->hwcdrv_get_info (NULL, NULL, &cpcN_npics, NULL, NULL);
6924f645668Schristos return hwcdrv_driver;
6934f645668Schristos }
6944f645668Schristos hwcdrv_driver = &hwcdrv_default;
6954f645668Schristos return hwcdrv_driver;
6964f645668Schristos }
697