Home | History | Annotate | Line # | Download | only in common
      1  1.1.1.3  christos /* Copyright (C) 2021-2025 Free Software Foundation, Inc.
      2      1.1  christos    Contributed by Oracle.
      3      1.1  christos 
      4      1.1  christos    This file is part of GNU Binutils.
      5      1.1  christos 
      6      1.1  christos    This program is free software; you can redistribute it and/or modify
      7      1.1  christos    it under the terms of the GNU General Public License as published by
      8      1.1  christos    the Free Software Foundation; either version 3, or (at your option)
      9      1.1  christos    any later version.
     10      1.1  christos 
     11      1.1  christos    This program is distributed in the hope that it will be useful,
     12      1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14      1.1  christos    GNU General Public License for more details.
     15      1.1  christos 
     16      1.1  christos    You should have received a copy of the GNU General Public License
     17      1.1  christos    along with this program; if not, write to the Free Software
     18      1.1  christos    Foundation, 51 Franklin Street - Fifth Floor, Boston,
     19      1.1  christos    MA 02110-1301, USA.  */
     20      1.1  christos 
     21      1.1  christos /* Hardware counter profiling */
     22      1.1  christos #include "hwcdrv.h"
     23      1.1  christos #include "hwcfuncs.h"
     24      1.1  christos 
     25      1.1  christos /*---------------------------------------------------------------------------*/
     26      1.1  christos /* macros */
     27      1.1  christos 
     28      1.1  christos #define IS_GLOBAL           /* Mark global symbols */
     29      1.1  christos #define HWCDRV_API static   /* Mark functions used by hwcdrv API */
     30      1.1  christos 
     31      1.1  christos /*---------------------------------------------------------------------------*/
     32      1.1  christos /* static variables */
     33      1.1  christos static uint_t cpcN_npics;
     34      1.1  christos static char hwcfuncs_errmsg_buf[1024];
     35      1.1  christos static int hwcfuncs_errmsg_enabled = 1;
     36      1.1  christos static int hwcfuncs_errmsg_valid;
     37      1.1  christos 
     38      1.1  christos /* --- user counter selections and options */
     39      1.1  christos static unsigned hwcdef_cnt; /* number of *active* hardware counters */
     40      1.1  christos static Hwcentry hwcdef[MAX_PICS]; /* HWC definitions */
     41      1.1  christos static Hwcentry *hwctable[MAX_PICS]; /* HWC definitions */
     42      1.1  christos 
     43      1.1  christos /* --- drivers --- */
     44      1.1  christos 
     45      1.1  christos // default driver
     46      1.1  christos 
     47      1.1  christos HWCDRV_API int
     48      1.1  christos hwcdrv_init (hwcfuncs_abort_fn_t abort_ftn, int* tsd_sz)
     49      1.1  christos {
     50      1.1  christos   return -1;
     51      1.1  christos }
     52      1.1  christos 
     53      1.1  christos HWCDRV_API void
     54      1.1  christos hwcdrv_get_info (
     55      1.1  christos 		 int * cpuver, const char ** cciname,
     56      1.1  christos 		 uint_t * npics, const char ** docref, uint64_t* support) { }
     57      1.1  christos 
     58      1.1  christos HWCDRV_API int
     59      1.1  christos hwcdrv_enable_mt (hwcfuncs_tsd_get_fn_t tsd_ftn)
     60      1.1  christos {
     61      1.1  christos   return -1;
     62      1.1  christos }
     63      1.1  christos 
     64      1.1  christos HWCDRV_API int
     65      1.1  christos hwcdrv_get_descriptions (hwcf_hwc_cb_t *hwc_find_action,
     66  1.1.1.3  christos 			 hwcf_attr_cb_t *attr_find_action, Hwcentry *hwcdef)
     67      1.1  christos {
     68      1.1  christos   return 0;
     69      1.1  christos }
     70      1.1  christos 
     71      1.1  christos HWCDRV_API int
     72      1.1  christos hwcdrv_assign_regnos (Hwcentry *entries[], unsigned numctrs)
     73      1.1  christos {
     74      1.1  christos   return -1;
     75      1.1  christos }
     76      1.1  christos 
     77      1.1  christos HWCDRV_API int
     78      1.1  christos hwcdrv_create_counters (unsigned hwcdef_cnt, Hwcentry *hwcdef)
     79      1.1  christos {
     80      1.1  christos   return -1;
     81      1.1  christos }
     82      1.1  christos 
     83      1.1  christos HWCDRV_API int
     84      1.1  christos hwcdrv_read_events (hwc_event_t *events, hwc_event_samples_t*samples)
     85      1.1  christos {
     86      1.1  christos   return -1;
     87      1.1  christos }
     88      1.1  christos 
     89      1.1  christos HWCDRV_API int
     90      1.1  christos hwcdrv_start (void)
     91      1.1  christos {
     92      1.1  christos   return -1;
     93      1.1  christos }
     94      1.1  christos 
     95      1.1  christos HWCDRV_API int
     96      1.1  christos hwcdrv_overflow (siginfo_t *si, hwc_event_t *s, hwc_event_t *t)
     97      1.1  christos {
     98      1.1  christos   return 0;
     99      1.1  christos }
    100      1.1  christos 
    101      1.1  christos HWCDRV_API int
    102      1.1  christos hwcdrv_sighlr_restart (const hwc_event_t *sample)
    103      1.1  christos {
    104      1.1  christos   return -1;
    105      1.1  christos }
    106      1.1  christos 
    107      1.1  christos HWCDRV_API int
    108      1.1  christos hwcdrv_lwp_suspend (void)
    109      1.1  christos {
    110      1.1  christos   return -1;
    111      1.1  christos }
    112      1.1  christos 
    113      1.1  christos HWCDRV_API int
    114      1.1  christos hwcdrv_lwp_resume (void)
    115      1.1  christos {
    116      1.1  christos   return -1;
    117      1.1  christos }
    118      1.1  christos 
    119      1.1  christos HWCDRV_API int
    120      1.1  christos hwcdrv_free_counters (void)
    121      1.1  christos {
    122      1.1  christos   return 0;
    123      1.1  christos }
    124      1.1  christos 
    125      1.1  christos HWCDRV_API int
    126      1.1  christos hwcdrv_lwp_init (void)
    127      1.1  christos {
    128      1.1  christos   return 0;
    129      1.1  christos }
    130      1.1  christos 
    131      1.1  christos HWCDRV_API void
    132      1.1  christos hwcdrv_lwp_fini (void) { }
    133      1.1  christos 
    134      1.1  christos static hwcdrv_api_t hwcdrv_default = {
    135      1.1  christos   hwcdrv_init,
    136      1.1  christos   hwcdrv_get_info,
    137      1.1  christos   hwcdrv_enable_mt,
    138      1.1  christos   hwcdrv_get_descriptions,
    139      1.1  christos   hwcdrv_assign_regnos,
    140      1.1  christos   hwcdrv_create_counters,
    141      1.1  christos   hwcdrv_start,
    142      1.1  christos   hwcdrv_overflow,
    143      1.1  christos   hwcdrv_read_events,
    144      1.1  christos   hwcdrv_sighlr_restart,
    145      1.1  christos   hwcdrv_lwp_suspend,
    146      1.1  christos   hwcdrv_lwp_resume,
    147      1.1  christos   hwcdrv_free_counters,
    148      1.1  christos   hwcdrv_lwp_init,
    149      1.1  christos   hwcdrv_lwp_fini,
    150      1.1  christos   -1                        // hwcdrv_init_status
    151      1.1  christos };
    152      1.1  christos 
    153      1.1  christos static hwcdrv_api_t *hwcdrv_driver = &hwcdrv_default;
    154      1.1  christos 
    155      1.1  christos 
    156      1.1  christos /*---------------------------------------------------------------------------*/
    157      1.1  christos /* misc */
    158      1.1  christos 
    159      1.1  christos /* print a counter definition (for debugging) */
    160      1.1  christos static void
    161      1.1  christos ctrdefprint (int dbg_lvl, const char * hdr, Hwcentry*phwcdef)
    162      1.1  christos {
    163      1.1  christos   TprintfT (dbg_lvl, "%s: name='%s', int_name='%s',"
    164      1.1  christos 	    " reg_num=%d, timecvt=%d, memop=%d, "
    165  1.1.1.3  christos 	    "interval=%d, tag=%u\n",
    166      1.1  christos 	    hdr, phwcdef->name, phwcdef->int_name, phwcdef->reg_num,
    167      1.1  christos 	    phwcdef->timecvt, phwcdef->memop, phwcdef->val,
    168  1.1.1.3  christos 	    phwcdef->sort_order);
    169      1.1  christos }
    170      1.1  christos 
    171      1.1  christos /*---------------------------------------------------------------------------*/
    172      1.1  christos /* errmsg buffering */
    173      1.1  christos 
    174      1.1  christos /* errmsg buffering is needed only because the most descriptive error
    175      1.1  christos    messages from CPC are delivered using a callback mechanism.
    176      1.1  christos    hwcfuncs_errmsg_get() should only be used during initialization, and
    177      1.1  christos    ideally,  only to provide feedback to an end user when his counters can't
    178      1.1  christos    be bound to HW.
    179      1.1  christos  */
    180      1.1  christos IS_GLOBAL char *
    181      1.1  christos hwcfuncs_errmsg_get (char *buf, size_t bufsize, int enable)
    182      1.1  christos {
    183      1.1  christos   hwcfuncs_errmsg_enabled = 0;
    184      1.1  christos   if (buf && bufsize)
    185      1.1  christos     {
    186      1.1  christos       if (hwcfuncs_errmsg_valid)
    187      1.1  christos 	{
    188      1.1  christos 	  strncpy (buf, hwcfuncs_errmsg_buf, bufsize);
    189      1.1  christos 	  buf[bufsize - 1] = 0;
    190      1.1  christos 	}
    191      1.1  christos       else
    192      1.1  christos 	*buf = 0;
    193      1.1  christos     }
    194      1.1  christos   hwcfuncs_errmsg_buf[0] = 0;
    195      1.1  christos   hwcfuncs_errmsg_valid = 0;
    196      1.1  christos   hwcfuncs_errmsg_enabled = enable;
    197      1.1  christos   return buf;
    198      1.1  christos }
    199      1.1  christos 
    200      1.1  christos /* used by cpc to log an error */
    201  1.1.1.3  christos static void
    202      1.1  christos hwcfuncs_int_capture_errmsg (const char *fn, int subcode,
    203      1.1  christos 			     const char *fmt, va_list ap)
    204      1.1  christos {
    205      1.1  christos   if (hwcfuncs_errmsg_enabled &&
    206      1.1  christos       !hwcfuncs_errmsg_valid)
    207      1.1  christos     {
    208      1.1  christos       vsnprintf (hwcfuncs_errmsg_buf, sizeof (hwcfuncs_errmsg_buf), fmt, ap);
    209      1.1  christos       TprintfT (DBG_LT0, "hwcfuncs: cpcN_capture_errmsg(): %s\n",
    210      1.1  christos 		hwcfuncs_errmsg_buf);
    211      1.1  christos       hwcfuncs_errmsg_valid = 1;
    212      1.1  christos     }
    213      1.1  christos   return;
    214      1.1  christos }
    215      1.1  christos 
    216      1.1  christos /* Log an internal error to the CPC error buffer.
    217      1.1  christos  * Note: only call this during init functions.
    218      1.1  christos  * Note: when most cpc calls fail, they will call cpcN_capture_errmsg()
    219      1.1  christos  *   directly, so only call logerr() when a non-cpc function fails.
    220      1.1  christos  */
    221      1.1  christos IS_GLOBAL void
    222      1.1  christos hwcfuncs_int_logerr (const char *format, ...)
    223      1.1  christos {
    224      1.1  christos   va_list va;
    225      1.1  christos   va_start (va, format);
    226      1.1  christos   hwcfuncs_int_capture_errmsg ("logerr", 0, format, va);
    227      1.1  christos   va_end (va);
    228      1.1  christos }
    229      1.1  christos 
    230      1.1  christos /* utils to parse counter strings */
    231      1.1  christos static void
    232      1.1  christos clear_hwcdefs ()
    233      1.1  christos {
    234      1.1  christos   for (unsigned idx = 0; idx < MAX_PICS; idx++)
    235      1.1  christos     {
    236      1.1  christos       static Hwcentry empty;
    237      1.1  christos       hwcdef[idx] = empty; // leaks strings and reg_list array
    238      1.1  christos       hwcdef[idx].reg_num = REGNO_ANY;
    239      1.1  christos       hwcdef[idx].val = -1;
    240      1.1  christos       hwcdef[idx].sort_order = -1;
    241      1.1  christos     }
    242      1.1  christos }
    243      1.1  christos 
    244      1.1  christos /* initialize hwcdef[] based on user's counter definitions */
    245      1.1  christos static int
    246      1.1  christos process_data_descriptor (const char *defstring)
    247      1.1  christos {
    248      1.1  christos   /*
    249      1.1  christos    * <defstring> format should be of format
    250      1.1  christos    *  :%s:%s:0x%x:%d:%lld:%d:%d:0x%x[,%s...repeat for each ctr]
    251      1.1  christos    * where the counter fields are:
    252      1.1  christos    *  :<userName>:<internalCtr>:<register>:<timeoutVal>[:m<min_time>]:<tag>:<timecvt>:<memop>
    253      1.1  christos    * See Coll_Ctrl::build_data_desc().
    254      1.1  christos    */
    255      1.1  christos   int err = 0;
    256      1.1  christos   char *ds = NULL;
    257      1.1  christos   char *dsp = NULL;
    258      1.1  christos   unsigned idx;
    259      1.1  christos 
    260      1.1  christos   clear_hwcdefs ();
    261      1.1  christos   if (!defstring || !strlen (defstring))
    262  1.1.1.2  christos     return HWCFUNCS_ERROR_HWCARGS;
    263      1.1  christos   ds = strdup (defstring);
    264      1.1  christos   if (!ds)
    265  1.1.1.2  christos     return HWCFUNCS_ERROR_HWCINIT;
    266      1.1  christos   dsp = ds;
    267      1.1  christos   for (idx = 0; idx < MAX_PICS && *dsp; idx++)
    268      1.1  christos     {
    269      1.1  christos       char *name = NULL;
    270      1.1  christos       char *int_name = NULL;
    271      1.1  christos       regno_t reg = REGNO_ANY;
    272      1.1  christos       ABST_type memop = ABST_NONE;
    273      1.1  christos       int interval = 0;
    274      1.1  christos       int timecvt = 0;
    275      1.1  christos       unsigned sort_order = (unsigned) - 1;
    276      1.1  christos 
    277  1.1.1.2  christos       // Read use_perf_event_type, type, config
    278  1.1.1.2  christos       hwcdef[idx].use_perf_event_type = (int) strtol (dsp, &dsp, 0);
    279  1.1.1.2  christos       if (*dsp++ != ':')
    280  1.1.1.2  christos 	{
    281  1.1.1.2  christos 	  err = HWCFUNCS_ERROR_HWCARGS;
    282  1.1.1.2  christos 	  break;
    283  1.1.1.2  christos 	}
    284  1.1.1.2  christos       hwcdef[idx].type = (int) strtol (dsp, &dsp, 0);
    285  1.1.1.2  christos       if (*dsp++ != ':')
    286  1.1.1.2  christos 	{
    287  1.1.1.2  christos 	  err = HWCFUNCS_ERROR_HWCARGS;
    288  1.1.1.2  christos 	  break;
    289  1.1.1.2  christos 	}
    290  1.1.1.2  christos       hwcdef[idx].config = strtol (dsp, &dsp, 0);
    291  1.1.1.2  christos       if (*dsp++ != ':')
    292  1.1.1.2  christos 	{
    293  1.1.1.2  christos 	  err = HWCFUNCS_ERROR_HWCARGS;
    294  1.1.1.2  christos 	  break;
    295  1.1.1.2  christos 	}
    296  1.1.1.3  christos       hwcdef[idx].config1 = strtol (dsp, &dsp, 0);
    297  1.1.1.3  christos       if (*dsp++ != ':')
    298  1.1.1.3  christos 	{
    299  1.1.1.3  christos 	  err = HWCFUNCS_ERROR_HWCARGS;
    300  1.1.1.3  christos 	  break;
    301  1.1.1.3  christos 	}
    302  1.1.1.2  christos 
    303      1.1  christos       /* name */
    304      1.1  christos       name = dsp;
    305      1.1  christos       dsp = strchr (dsp, ':');
    306      1.1  christos       if (dsp == NULL)
    307      1.1  christos 	{
    308      1.1  christos 	  err = HWCFUNCS_ERROR_HWCARGS;
    309  1.1.1.2  christos 	  break;
    310      1.1  christos 	}
    311      1.1  christos       *dsp++ = (char) 0;
    312      1.1  christos 
    313      1.1  christos       /* int_name */
    314      1.1  christos       int_name = dsp;
    315      1.1  christos       dsp = strchr (dsp, ':');
    316      1.1  christos       if (dsp == NULL)
    317      1.1  christos 	{
    318      1.1  christos 	  err = HWCFUNCS_ERROR_HWCARGS;
    319  1.1.1.2  christos 	  break;
    320      1.1  christos 	}
    321      1.1  christos       *dsp++ = (char) 0;
    322      1.1  christos 
    323      1.1  christos       /* reg_num */
    324      1.1  christos       reg = (int) strtol (dsp, &dsp, 0);
    325      1.1  christos       if (*dsp++ != ':')
    326      1.1  christos 	{
    327      1.1  christos 	  err = HWCFUNCS_ERROR_HWCARGS;
    328  1.1.1.2  christos 	  break;
    329      1.1  christos 	}
    330      1.1  christos       if (reg < 0 && reg != -1)
    331      1.1  christos 	{
    332      1.1  christos 	  err = HWCFUNCS_ERROR_HWCARGS;
    333  1.1.1.2  christos 	  break;
    334      1.1  christos 	}
    335      1.1  christos       if (reg >= 0)
    336      1.1  christos 	hwcdef[idx].reg_num = reg;
    337      1.1  christos 
    338      1.1  christos       /* val */
    339      1.1  christos       interval = (int) strtol (dsp, &dsp, 0);
    340      1.1  christos       if (*dsp++ != ':')
    341      1.1  christos 	{
    342      1.1  christos 	  err = HWCFUNCS_ERROR_HWCARGS;
    343  1.1.1.2  christos 	  break;
    344      1.1  christos 	}
    345      1.1  christos       if (interval < 0)
    346      1.1  christos 	{
    347      1.1  christos 	  err = HWCFUNCS_ERROR_HWCARGS;
    348  1.1.1.2  christos 	  break;
    349      1.1  christos 	}
    350      1.1  christos       hwcdef[idx].val = interval;
    351      1.1  christos 
    352      1.1  christos       /* min_time */
    353      1.1  christos       if (*dsp == 'm')
    354      1.1  christos 	{
    355      1.1  christos 	  long long tmp_ll = 0;
    356      1.1  christos 	  dsp++;
    357      1.1  christos 	  tmp_ll = strtoll (dsp, &dsp, 0);
    358      1.1  christos 	  if (*dsp++ != ':')
    359      1.1  christos 	    {
    360      1.1  christos 	      err = HWCFUNCS_ERROR_HWCARGS;
    361  1.1.1.2  christos 	      break;
    362      1.1  christos 	    }
    363      1.1  christos 	  if (tmp_ll < 0)
    364      1.1  christos 	    {
    365      1.1  christos 	      err = HWCFUNCS_ERROR_HWCARGS;
    366  1.1.1.2  christos 	      break;
    367      1.1  christos 	    }
    368      1.1  christos 	  hwcdef[idx].min_time = tmp_ll;
    369      1.1  christos 	}
    370      1.1  christos       else
    371      1.1  christos 	hwcdef[idx].min_time = 0;
    372      1.1  christos 
    373      1.1  christos       /* sort_order */
    374      1.1  christos       sort_order = (int) strtoul (dsp, &dsp, 0);
    375      1.1  christos       if (*dsp++ != ':')
    376      1.1  christos 	{
    377      1.1  christos 	  err = HWCFUNCS_ERROR_HWCARGS;
    378  1.1.1.2  christos 	  break;
    379      1.1  christos 	}
    380      1.1  christos       hwcdef[idx].sort_order = sort_order;
    381      1.1  christos 
    382      1.1  christos       /* timecvt */
    383      1.1  christos       timecvt = (int) strtol (dsp, &dsp, 0);
    384      1.1  christos       if (*dsp++ != ':')
    385      1.1  christos 	{
    386      1.1  christos 	  err = HWCFUNCS_ERROR_HWCARGS;
    387  1.1.1.2  christos 	  break;
    388      1.1  christos 	}
    389      1.1  christos       hwcdef[idx].timecvt = timecvt;
    390      1.1  christos 
    391      1.1  christos       /* memop */
    392      1.1  christos       memop = (ABST_type) strtol (dsp, &dsp, 0);
    393      1.1  christos       if (*dsp != 0 && *dsp++ != ',')
    394      1.1  christos 	{
    395      1.1  christos 	  err = HWCFUNCS_ERROR_HWCARGS;
    396  1.1.1.2  christos 	  break;
    397      1.1  christos 	}
    398      1.1  christos       hwcdef[idx].memop = memop;
    399      1.1  christos       if (*name)
    400      1.1  christos 	hwcdef[idx].name = strdup (name);
    401      1.1  christos       else
    402      1.1  christos 	hwcdef[idx].name = strdup (int_name);
    403      1.1  christos       if (*int_name)
    404      1.1  christos 	hwcdef[idx].int_name = strdup (int_name);
    405      1.1  christos       else
    406      1.1  christos 	hwcdef[idx].int_name = strdup (name);
    407      1.1  christos       ctrdefprint (DBG_LT1, "hwcfuncs: process_data_descriptor", &hwcdef[idx]);
    408      1.1  christos     }
    409      1.1  christos 
    410      1.1  christos   if (*dsp)
    411  1.1.1.2  christos     err = HWCFUNCS_ERROR_HWCARGS;
    412  1.1.1.2  christos   if (err != 0)
    413  1.1.1.2  christos     logerr (GTXT ("Data descriptor syntax error near `%s'\n"), dsp);
    414      1.1  christos   else
    415  1.1.1.2  christos     hwcdef_cnt = idx;
    416      1.1  christos   free (ds);
    417      1.1  christos   return err;
    418      1.1  christos }
    419      1.1  christos 
    420      1.1  christos /* initialize hwcdef[] based on user's counter definitions */
    421      1.1  christos static int
    422      1.1  christos process_hwcentrylist (const Hwcentry* entries[], unsigned numctrs)
    423      1.1  christos {
    424      1.1  christos   int err = 0;
    425      1.1  christos   clear_hwcdefs ();
    426      1.1  christos   if (numctrs > cpcN_npics)
    427      1.1  christos     {
    428      1.1  christos       logerr (GTXT ("More than %d counters were specified\n"), cpcN_npics); /*!*/
    429      1.1  christos       return HWCFUNCS_ERROR_HWCARGS;
    430      1.1  christos     }
    431      1.1  christos   for (unsigned idx = 0; idx < numctrs; idx++)
    432      1.1  christos     {
    433      1.1  christos       Hwcentry *phwcdef = &hwcdef[idx];
    434      1.1  christos       *phwcdef = *entries[idx];
    435      1.1  christos       if (phwcdef->name)
    436      1.1  christos 	phwcdef->name = strdup (phwcdef->name);
    437      1.1  christos       else
    438      1.1  christos 	phwcdef->name = "NULL";
    439      1.1  christos       if (phwcdef->int_name)
    440      1.1  christos 	phwcdef->int_name = strdup (phwcdef->int_name);
    441      1.1  christos       else
    442      1.1  christos 	phwcdef->int_name = "NULL";
    443      1.1  christos       if (phwcdef->val < 0)
    444      1.1  christos 	{
    445      1.1  christos 	  logerr (GTXT ("Negative interval specified for HW counter `%s'\n"), /*!*/
    446      1.1  christos 		  phwcdef->name);
    447      1.1  christos 	  err = HWCFUNCS_ERROR_HWCARGS;
    448      1.1  christos 	  break;
    449      1.1  christos 	}
    450      1.1  christos       ctrdefprint (DBG_LT1, "hwcfuncs: process_hwcentrylist", phwcdef);
    451      1.1  christos     }
    452      1.1  christos   if (!err)
    453      1.1  christos     hwcdef_cnt = numctrs;
    454      1.1  christos   return err;
    455      1.1  christos }
    456      1.1  christos 
    457      1.1  christos /* see hwcfuncs.h */
    458      1.1  christos IS_GLOBAL void *
    459      1.1  christos hwcfuncs_parse_attrs (const char *countername, hwcfuncs_attr_t attrs[],
    460      1.1  christos 		      unsigned max_attrs, uint_t *pnum_attrs, char**errstring)
    461      1.1  christos {
    462      1.1  christos   char *head = NULL;
    463      1.1  christos   char *tail = NULL;
    464      1.1  christos   uint_t nattrs = 0;
    465      1.1  christos   char *counter_copy;
    466      1.1  christos   int success = 0;
    467      1.1  christos   char errbuf[512];
    468      1.1  christos   errbuf[0] = 0;
    469      1.1  christos   counter_copy = strdup (countername);
    470      1.1  christos 
    471      1.1  christos   /* advance pointer to first attribute */
    472      1.1  christos   tail = strchr (counter_copy, HWCFUNCS_PARSE_ATTR);
    473      1.1  christos   if (tail)
    474      1.1  christos     *tail = 0;
    475      1.1  christos 
    476      1.1  christos   /* remove regno and value, if supplied */
    477      1.1  christos   {
    478      1.1  christos     char *tmp = strchr (counter_copy, HWCFUNCS_PARSE_REGNUM);
    479      1.1  christos     if (tmp)
    480      1.1  christos       *tmp = 0;
    481      1.1  christos     tmp = strchr (counter_copy, HWCFUNCS_PARSE_VALUE);
    482      1.1  christos     if (tmp)
    483      1.1  christos       *tmp = 0;
    484      1.1  christos   }
    485      1.1  christos 
    486      1.1  christos   while (tail)
    487      1.1  christos     {
    488      1.1  christos       char *pch;
    489      1.1  christos       if (nattrs >= max_attrs)
    490      1.1  christos 	{
    491      1.1  christos 	  snprintf (errbuf, sizeof (errbuf),
    492      1.1  christos 		    GTXT ("Too many attributes defined in `%s'"),
    493      1.1  christos 		    countername);
    494      1.1  christos 	  goto mycpc2_parse_attrs_end;
    495      1.1  christos 	}
    496      1.1  christos       /* get attribute name */
    497      1.1  christos       head = tail + 1;
    498      1.1  christos       tail = strchr (head, HWCFUNCS_PARSE_EQUAL);
    499      1.1  christos       if (!tail)
    500      1.1  christos 	{
    501      1.1  christos 	  snprintf (errbuf, sizeof (errbuf),
    502      1.1  christos 		    GTXT ("Missing value for attribute `%s' in `%s'"),
    503      1.1  christos 		    head, countername);
    504      1.1  christos 	  goto mycpc2_parse_attrs_end;
    505      1.1  christos 	}
    506      1.1  christos       *tail = 0; /* null terminate current component */
    507      1.1  christos       attrs[nattrs].ca_name = head;
    508      1.1  christos 
    509      1.1  christos       /* get attribute value */
    510      1.1  christos       head = tail + 1;
    511      1.1  christos       tail = strchr (head, HWCFUNCS_PARSE_ATTR);
    512      1.1  christos       if (tail)
    513      1.1  christos 	*tail = 0; /* null terminate current component */
    514      1.1  christos       attrs[nattrs].ca_val = strtoull (head, &pch, 0);
    515      1.1  christos       if (pch == head)
    516      1.1  christos 	{
    517      1.1  christos 	  snprintf (errbuf, sizeof (errbuf),
    518      1.1  christos 		    GTXT ("Illegal value for attribute `%s' in `%s'"),
    519      1.1  christos 		    attrs[nattrs].ca_name, countername);
    520      1.1  christos 	  goto mycpc2_parse_attrs_end;
    521      1.1  christos 	}
    522      1.1  christos       TprintfT (DBG_LT0, "hwcfuncs: pic_: '%s', attribute[%u]"
    523      1.1  christos 		" '%s' = 0x%llx\n",
    524      1.1  christos 		counter_copy, nattrs, attrs[nattrs].ca_name,
    525      1.1  christos 		(long long unsigned int) attrs[nattrs].ca_val);
    526      1.1  christos 
    527      1.1  christos       nattrs++;
    528      1.1  christos     }
    529      1.1  christos   success = 1;
    530      1.1  christos 
    531      1.1  christos mycpc2_parse_attrs_end:
    532      1.1  christos   *pnum_attrs = nattrs;
    533      1.1  christos   if (success)
    534      1.1  christos     {
    535      1.1  christos       if (errstring)
    536      1.1  christos 	*errstring = NULL;
    537      1.1  christos     }
    538      1.1  christos   else
    539      1.1  christos     {
    540      1.1  christos       if (errstring)
    541      1.1  christos 	*errstring = strdup (errbuf);
    542      1.1  christos       free (counter_copy);
    543      1.1  christos       counter_copy = NULL;
    544      1.1  christos     }
    545      1.1  christos   return counter_copy;
    546      1.1  christos }
    547      1.1  christos 
    548      1.1  christos IS_GLOBAL void
    549      1.1  christos hwcfuncs_parse_ctr (const char *counter_def, int *pplus, char **pnameOnly,
    550      1.1  christos 		    char **pattrs, char **pregstr, regno_t *pregno)
    551      1.1  christos {
    552      1.1  christos   char *nameptr, *copy, *slash, *attr_delim;
    553      1.1  christos   int plus;
    554      1.1  christos   regno_t regno;
    555      1.1  christos   nameptr = copy = strdup (counter_def);
    556      1.1  christos 
    557      1.1  christos   /* plus */
    558      1.1  christos   plus = 0;
    559      1.1  christos   if (nameptr[0] == HWCFUNCS_PARSE_BACKTRACK)
    560      1.1  christos     {
    561      1.1  christos       plus = 1;
    562      1.1  christos       nameptr++;
    563      1.1  christos     }
    564      1.1  christos   else if (nameptr[0] == HWCFUNCS_PARSE_BACKTRACK_OFF)
    565      1.1  christos     {
    566      1.1  christos       plus = -1;
    567      1.1  christos       nameptr++;
    568      1.1  christos     }
    569      1.1  christos   if (pplus)
    570      1.1  christos     *pplus = plus;
    571      1.1  christos 
    572      1.1  christos   /* regno */
    573      1.1  christos   regno = REGNO_ANY;
    574      1.1  christos   if (pregstr)
    575      1.1  christos     *pregstr = NULL;
    576      1.1  christos   slash = strchr (nameptr, HWCFUNCS_PARSE_REGNUM);
    577      1.1  christos   if (slash != NULL)
    578      1.1  christos     {
    579      1.1  christos       /* the remaining string should be a number > 0 */
    580      1.1  christos       if (pregstr)
    581      1.1  christos 	*pregstr = strdup (slash);
    582      1.1  christos       char *endchar = NULL;
    583      1.1  christos       regno = (regno_t) strtol (slash + 1, &endchar, 0);
    584      1.1  christos       if (*endchar != 0)
    585      1.1  christos 	regno = -2;
    586      1.1  christos       if (*(slash + 1) == '-')
    587      1.1  christos 	regno = -2;
    588      1.1  christos       /* terminate previous element up to slash */
    589      1.1  christos       *slash = 0;
    590      1.1  christos     }
    591      1.1  christos   if (pregno)
    592      1.1  christos     *pregno = regno;
    593      1.1  christos 
    594      1.1  christos   /* attrs */
    595      1.1  christos   if (pattrs)
    596      1.1  christos     *pattrs = NULL;
    597      1.1  christos   attr_delim = strchr (nameptr, HWCFUNCS_PARSE_ATTR);
    598      1.1  christos   if (attr_delim != NULL)
    599      1.1  christos     {
    600      1.1  christos       if (pattrs)
    601      1.1  christos 	*pattrs = strdup (attr_delim);
    602      1.1  christos       /* terminate previous element up to attr_delim */
    603      1.1  christos       *attr_delim++ = 0;
    604      1.1  christos     }
    605      1.1  christos   if (pnameOnly)
    606      1.1  christos     *pnameOnly = strdup (nameptr);
    607      1.1  christos   free (copy);
    608      1.1  christos }
    609      1.1  christos 
    610      1.1  christos /* create counters */
    611      1.1  christos IS_GLOBAL int
    612      1.1  christos hwcfuncs_bind_descriptor (const char *defstring)
    613      1.1  christos {
    614      1.1  christos   int err = process_data_descriptor (defstring);
    615      1.1  christos   if (err)
    616      1.1  christos     {
    617      1.1  christos       TprintfT (DBG_LT0, "hwcfuncs: ERROR: hwcfuncs_bind_descriptor failed\n");
    618      1.1  christos       return err;
    619      1.1  christos     }
    620      1.1  christos   err = hwcdrv_driver->hwcdrv_create_counters (hwcdef_cnt, hwcdef);
    621      1.1  christos   return err;
    622      1.1  christos }
    623      1.1  christos 
    624      1.1  christos /* see hwcfuncs.h */
    625      1.1  christos IS_GLOBAL int
    626      1.1  christos hwcfuncs_bind_hwcentry (const Hwcentry* entries[], unsigned numctrs)
    627      1.1  christos {
    628      1.1  christos   int err = -1;
    629      1.1  christos   err = process_hwcentrylist (entries, numctrs);
    630      1.1  christos   if (err)
    631      1.1  christos     {
    632      1.1  christos       TprintfT (DBG_LT0, "hwcfuncs: ERROR: hwcfuncs_bind_hwcentry\n");
    633      1.1  christos       return err;
    634      1.1  christos     }
    635      1.1  christos   err = hwcdrv_driver->hwcdrv_create_counters (hwcdef_cnt, hwcdef);
    636      1.1  christos   return err;
    637      1.1  christos }
    638      1.1  christos 
    639      1.1  christos /* see hwcfuncs.h */
    640      1.1  christos IS_GLOBAL Hwcentry **
    641      1.1  christos hwcfuncs_get_ctrs (unsigned *defcnt)
    642      1.1  christos {
    643      1.1  christos   if (defcnt)
    644      1.1  christos     *defcnt = hwcdef_cnt;
    645      1.1  christos   return hwctable;
    646      1.1  christos }
    647      1.1  christos 
    648      1.1  christos extern hwcdrv_api_t hwcdrv_pcl_api;
    649      1.1  christos static int hwcdrv_driver_inited = 0;
    650      1.1  christos 
    651      1.1  christos hwcdrv_api_t *
    652      1.1  christos get_hwcdrv ()
    653      1.1  christos {
    654      1.1  christos   if (hwcdrv_driver_inited)
    655      1.1  christos     return hwcdrv_driver;
    656      1.1  christos   hwcdrv_driver_inited = 1;
    657      1.1  christos   cpcN_npics = 0;
    658      1.1  christos   for (int i = 0; i < MAX_PICS; i++)
    659      1.1  christos     hwctable[i] = &hwcdef[i];
    660      1.1  christos   hwcdrv_driver = &hwcdrv_pcl_api;
    661      1.1  christos   hwcdrv_driver->hwcdrv_init_status = hwcdrv_driver->hwcdrv_init (NULL, NULL);
    662      1.1  christos   if (hwcdrv_driver->hwcdrv_init_status == 0)
    663      1.1  christos     {
    664      1.1  christos       hwcdrv_driver->hwcdrv_get_info (NULL, NULL, &cpcN_npics, NULL, NULL);
    665      1.1  christos       return hwcdrv_driver;
    666      1.1  christos     }
    667      1.1  christos   hwcdrv_driver = &hwcdrv_default;
    668      1.1  christos   return hwcdrv_driver;
    669      1.1  christos }
    670