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