Remove Debian from SECURITY.txt
[binutils-gdb.git] / gprofng / common / hwcfuncs.c
blob750db1030aaa470422378325382a1ff2dca878df
1 /* Copyright (C) 2021-2024 Free Software Foundation, Inc.
2 Contributed by Oracle.
4 This file is part of GNU Binutils.
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.
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.
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. */
21 /* Hardware counter profiling */
22 #include "hwcdrv.h"
23 #include "hwcfuncs.h"
25 /*---------------------------------------------------------------------------*/
26 /* macros */
28 #define IS_GLOBAL /* Mark global symbols */
29 #define HWCDRV_API static /* Mark functions used by hwcdrv API */
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;
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 */
43 /* --- drivers --- */
45 // default driver
47 HWCDRV_API int
48 hwcdrv_init (hwcfuncs_abort_fn_t abort_ftn, int* tsd_sz)
50 return -1;
53 HWCDRV_API void
54 hwcdrv_get_info (
55 int * cpuver, const char ** cciname,
56 uint_t * npics, const char ** docref, uint64_t* support) { }
58 HWCDRV_API int
59 hwcdrv_enable_mt (hwcfuncs_tsd_get_fn_t tsd_ftn)
61 return -1;
64 HWCDRV_API int
65 hwcdrv_get_descriptions (hwcf_hwc_cb_t *hwc_find_action,
66 hwcf_attr_cb_t *attr_find_action, Hwcentry *hwcdef)
68 return 0;
71 HWCDRV_API int
72 hwcdrv_assign_regnos (Hwcentry *entries[], unsigned numctrs)
74 return -1;
77 HWCDRV_API int
78 hwcdrv_create_counters (unsigned hwcdef_cnt, Hwcentry *hwcdef)
80 return -1;
83 HWCDRV_API int
84 hwcdrv_read_events (hwc_event_t *events, hwc_event_samples_t*samples)
86 return -1;
89 HWCDRV_API int
90 hwcdrv_start (void)
92 return -1;
95 HWCDRV_API int
96 hwcdrv_overflow (siginfo_t *si, hwc_event_t *s, hwc_event_t *t)
98 return 0;
101 HWCDRV_API int
102 hwcdrv_sighlr_restart (const hwc_event_t *sample)
104 return -1;
107 HWCDRV_API int
108 hwcdrv_lwp_suspend (void)
110 return -1;
113 HWCDRV_API int
114 hwcdrv_lwp_resume (void)
116 return -1;
119 HWCDRV_API int
120 hwcdrv_free_counters (void)
122 return 0;
125 HWCDRV_API int
126 hwcdrv_lwp_init (void)
128 return 0;
131 HWCDRV_API void
132 hwcdrv_lwp_fini (void) { }
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
153 static hwcdrv_api_t *hwcdrv_driver = &hwcdrv_default;
156 /*---------------------------------------------------------------------------*/
157 /* misc */
159 /* print a counter definition (for debugging) */
160 static void
161 ctrdefprint (int dbg_lvl, const char * hdr, Hwcentry*phwcdef)
163 TprintfT (dbg_lvl, "%s: name='%s', int_name='%s',"
164 " reg_num=%d, timecvt=%d, memop=%d, "
165 "interval=%d, tag=%u\n",
166 hdr, phwcdef->name, phwcdef->int_name, phwcdef->reg_num,
167 phwcdef->timecvt, phwcdef->memop, phwcdef->val,
168 phwcdef->sort_order);
171 /*---------------------------------------------------------------------------*/
172 /* errmsg buffering */
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.
180 IS_GLOBAL char *
181 hwcfuncs_errmsg_get (char *buf, size_t bufsize, int enable)
183 hwcfuncs_errmsg_enabled = 0;
184 if (buf && bufsize)
186 if (hwcfuncs_errmsg_valid)
188 strncpy (buf, hwcfuncs_errmsg_buf, bufsize);
189 buf[bufsize - 1] = 0;
191 else
192 *buf = 0;
194 hwcfuncs_errmsg_buf[0] = 0;
195 hwcfuncs_errmsg_valid = 0;
196 hwcfuncs_errmsg_enabled = enable;
197 return buf;
200 /* used by cpc to log an error */
201 static void
202 hwcfuncs_int_capture_errmsg (const char *fn, int subcode,
203 const char *fmt, va_list ap)
205 if (hwcfuncs_errmsg_enabled &&
206 !hwcfuncs_errmsg_valid)
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;
213 return;
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.
221 IS_GLOBAL void
222 hwcfuncs_int_logerr (const char *format, ...)
224 va_list va;
225 va_start (va, format);
226 hwcfuncs_int_capture_errmsg ("logerr", 0, format, va);
227 va_end (va);
230 /* utils to parse counter strings */
231 static void
232 clear_hwcdefs ()
234 for (unsigned idx = 0; idx < MAX_PICS; idx++)
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;
244 /* initialize hwcdef[] based on user's counter definitions */
245 static int
246 process_data_descriptor (const char *defstring)
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().
255 int err = 0;
256 char *ds = NULL;
257 char *dsp = NULL;
258 unsigned idx;
260 clear_hwcdefs ();
261 if (!defstring || !strlen (defstring))
262 return HWCFUNCS_ERROR_HWCARGS;
263 ds = strdup (defstring);
264 if (!ds)
265 return HWCFUNCS_ERROR_HWCINIT;
266 dsp = ds;
267 for (idx = 0; idx < MAX_PICS && *dsp; idx++)
269 char *name = NULL;
270 char *int_name = NULL;
271 regno_t reg = REGNO_ANY;
272 ABST_type memop = ABST_NONE;
273 int interval = 0;
274 int timecvt = 0;
275 unsigned sort_order = (unsigned) - 1;
277 // Read use_perf_event_type, type, config
278 hwcdef[idx].use_perf_event_type = (int) strtol (dsp, &dsp, 0);
279 if (*dsp++ != ':')
281 err = HWCFUNCS_ERROR_HWCARGS;
282 break;
284 hwcdef[idx].type = (int) strtol (dsp, &dsp, 0);
285 if (*dsp++ != ':')
287 err = HWCFUNCS_ERROR_HWCARGS;
288 break;
290 hwcdef[idx].config = strtol (dsp, &dsp, 0);
291 if (*dsp++ != ':')
293 err = HWCFUNCS_ERROR_HWCARGS;
294 break;
296 hwcdef[idx].config1 = strtol (dsp, &dsp, 0);
297 if (*dsp++ != ':')
299 err = HWCFUNCS_ERROR_HWCARGS;
300 break;
303 /* name */
304 name = dsp;
305 dsp = strchr (dsp, ':');
306 if (dsp == NULL)
308 err = HWCFUNCS_ERROR_HWCARGS;
309 break;
311 *dsp++ = (char) 0;
313 /* int_name */
314 int_name = dsp;
315 dsp = strchr (dsp, ':');
316 if (dsp == NULL)
318 err = HWCFUNCS_ERROR_HWCARGS;
319 break;
321 *dsp++ = (char) 0;
323 /* reg_num */
324 reg = (int) strtol (dsp, &dsp, 0);
325 if (*dsp++ != ':')
327 err = HWCFUNCS_ERROR_HWCARGS;
328 break;
330 if (reg < 0 && reg != -1)
332 err = HWCFUNCS_ERROR_HWCARGS;
333 break;
335 if (reg >= 0)
336 hwcdef[idx].reg_num = reg;
338 /* val */
339 interval = (int) strtol (dsp, &dsp, 0);
340 if (*dsp++ != ':')
342 err = HWCFUNCS_ERROR_HWCARGS;
343 break;
345 if (interval < 0)
347 err = HWCFUNCS_ERROR_HWCARGS;
348 break;
350 hwcdef[idx].val = interval;
352 /* min_time */
353 if (*dsp == 'm')
355 long long tmp_ll = 0;
356 dsp++;
357 tmp_ll = strtoll (dsp, &dsp, 0);
358 if (*dsp++ != ':')
360 err = HWCFUNCS_ERROR_HWCARGS;
361 break;
363 if (tmp_ll < 0)
365 err = HWCFUNCS_ERROR_HWCARGS;
366 break;
368 hwcdef[idx].min_time = tmp_ll;
370 else
371 hwcdef[idx].min_time = 0;
373 /* sort_order */
374 sort_order = (int) strtoul (dsp, &dsp, 0);
375 if (*dsp++ != ':')
377 err = HWCFUNCS_ERROR_HWCARGS;
378 break;
380 hwcdef[idx].sort_order = sort_order;
382 /* timecvt */
383 timecvt = (int) strtol (dsp, &dsp, 0);
384 if (*dsp++ != ':')
386 err = HWCFUNCS_ERROR_HWCARGS;
387 break;
389 hwcdef[idx].timecvt = timecvt;
391 /* memop */
392 memop = (ABST_type) strtol (dsp, &dsp, 0);
393 if (*dsp != 0 && *dsp++ != ',')
395 err = HWCFUNCS_ERROR_HWCARGS;
396 break;
398 hwcdef[idx].memop = memop;
399 if (*name)
400 hwcdef[idx].name = strdup (name);
401 else
402 hwcdef[idx].name = strdup (int_name);
403 if (*int_name)
404 hwcdef[idx].int_name = strdup (int_name);
405 else
406 hwcdef[idx].int_name = strdup (name);
407 ctrdefprint (DBG_LT1, "hwcfuncs: process_data_descriptor", &hwcdef[idx]);
410 if (*dsp)
411 err = HWCFUNCS_ERROR_HWCARGS;
412 if (err != 0)
413 logerr (GTXT ("Data descriptor syntax error near `%s'\n"), dsp);
414 else
415 hwcdef_cnt = idx;
416 free (ds);
417 return err;
420 /* initialize hwcdef[] based on user's counter definitions */
421 static int
422 process_hwcentrylist (const Hwcentry* entries[], unsigned numctrs)
424 int err = 0;
425 clear_hwcdefs ();
426 if (numctrs > cpcN_npics)
428 logerr (GTXT ("More than %d counters were specified\n"), cpcN_npics); /*!*/
429 return HWCFUNCS_ERROR_HWCARGS;
431 for (unsigned idx = 0; idx < numctrs; idx++)
433 Hwcentry *phwcdef = &hwcdef[idx];
434 *phwcdef = *entries[idx];
435 if (phwcdef->name)
436 phwcdef->name = strdup (phwcdef->name);
437 else
438 phwcdef->name = "NULL";
439 if (phwcdef->int_name)
440 phwcdef->int_name = strdup (phwcdef->int_name);
441 else
442 phwcdef->int_name = "NULL";
443 if (phwcdef->val < 0)
445 logerr (GTXT ("Negative interval specified for HW counter `%s'\n"), /*!*/
446 phwcdef->name);
447 err = HWCFUNCS_ERROR_HWCARGS;
448 break;
450 ctrdefprint (DBG_LT1, "hwcfuncs: process_hwcentrylist", phwcdef);
452 if (!err)
453 hwcdef_cnt = numctrs;
454 return err;
457 /* see hwcfuncs.h */
458 IS_GLOBAL void *
459 hwcfuncs_parse_attrs (const char *countername, hwcfuncs_attr_t attrs[],
460 unsigned max_attrs, uint_t *pnum_attrs, char**errstring)
462 char *head = NULL;
463 char *tail = NULL;
464 uint_t nattrs = 0;
465 char *counter_copy;
466 int success = 0;
467 char errbuf[512];
468 errbuf[0] = 0;
469 counter_copy = strdup (countername);
471 /* advance pointer to first attribute */
472 tail = strchr (counter_copy, HWCFUNCS_PARSE_ATTR);
473 if (tail)
474 *tail = 0;
476 /* remove regno and value, if supplied */
478 char *tmp = strchr (counter_copy, HWCFUNCS_PARSE_REGNUM);
479 if (tmp)
480 *tmp = 0;
481 tmp = strchr (counter_copy, HWCFUNCS_PARSE_VALUE);
482 if (tmp)
483 *tmp = 0;
486 while (tail)
488 char *pch;
489 if (nattrs >= max_attrs)
491 snprintf (errbuf, sizeof (errbuf),
492 GTXT ("Too many attributes defined in `%s'"),
493 countername);
494 goto mycpc2_parse_attrs_end;
496 /* get attribute name */
497 head = tail + 1;
498 tail = strchr (head, HWCFUNCS_PARSE_EQUAL);
499 if (!tail)
501 snprintf (errbuf, sizeof (errbuf),
502 GTXT ("Missing value for attribute `%s' in `%s'"),
503 head, countername);
504 goto mycpc2_parse_attrs_end;
506 *tail = 0; /* null terminate current component */
507 attrs[nattrs].ca_name = head;
509 /* get attribute value */
510 head = tail + 1;
511 tail = strchr (head, HWCFUNCS_PARSE_ATTR);
512 if (tail)
513 *tail = 0; /* null terminate current component */
514 attrs[nattrs].ca_val = strtoull (head, &pch, 0);
515 if (pch == head)
517 snprintf (errbuf, sizeof (errbuf),
518 GTXT ("Illegal value for attribute `%s' in `%s'"),
519 attrs[nattrs].ca_name, countername);
520 goto mycpc2_parse_attrs_end;
522 TprintfT (DBG_LT0, "hwcfuncs: pic_: '%s', attribute[%u]"
523 " '%s' = 0x%llx\n",
524 counter_copy, nattrs, attrs[nattrs].ca_name,
525 (long long unsigned int) attrs[nattrs].ca_val);
527 nattrs++;
529 success = 1;
531 mycpc2_parse_attrs_end:
532 *pnum_attrs = nattrs;
533 if (success)
535 if (errstring)
536 *errstring = NULL;
538 else
540 if (errstring)
541 *errstring = strdup (errbuf);
542 free (counter_copy);
543 counter_copy = NULL;
545 return counter_copy;
548 IS_GLOBAL void
549 hwcfuncs_parse_ctr (const char *counter_def, int *pplus, char **pnameOnly,
550 char **pattrs, char **pregstr, regno_t *pregno)
552 char *nameptr, *copy, *slash, *attr_delim;
553 int plus;
554 regno_t regno;
555 nameptr = copy = strdup (counter_def);
557 /* plus */
558 plus = 0;
559 if (nameptr[0] == HWCFUNCS_PARSE_BACKTRACK)
561 plus = 1;
562 nameptr++;
564 else if (nameptr[0] == HWCFUNCS_PARSE_BACKTRACK_OFF)
566 plus = -1;
567 nameptr++;
569 if (pplus)
570 *pplus = plus;
572 /* regno */
573 regno = REGNO_ANY;
574 if (pregstr)
575 *pregstr = NULL;
576 slash = strchr (nameptr, HWCFUNCS_PARSE_REGNUM);
577 if (slash != NULL)
579 /* the remaining string should be a number > 0 */
580 if (pregstr)
581 *pregstr = strdup (slash);
582 char *endchar = NULL;
583 regno = (regno_t) strtol (slash + 1, &endchar, 0);
584 if (*endchar != 0)
585 regno = -2;
586 if (*(slash + 1) == '-')
587 regno = -2;
588 /* terminate previous element up to slash */
589 *slash = 0;
591 if (pregno)
592 *pregno = regno;
594 /* attrs */
595 if (pattrs)
596 *pattrs = NULL;
597 attr_delim = strchr (nameptr, HWCFUNCS_PARSE_ATTR);
598 if (attr_delim != NULL)
600 if (pattrs)
601 *pattrs = strdup (attr_delim);
602 /* terminate previous element up to attr_delim */
603 *attr_delim++ = 0;
605 if (pnameOnly)
606 *pnameOnly = strdup (nameptr);
607 free (copy);
610 /* create counters */
611 IS_GLOBAL int
612 hwcfuncs_bind_descriptor (const char *defstring)
614 int err = process_data_descriptor (defstring);
615 if (err)
617 TprintfT (DBG_LT0, "hwcfuncs: ERROR: hwcfuncs_bind_descriptor failed\n");
618 return err;
620 err = hwcdrv_driver->hwcdrv_create_counters (hwcdef_cnt, hwcdef);
621 return err;
624 /* see hwcfuncs.h */
625 IS_GLOBAL int
626 hwcfuncs_bind_hwcentry (const Hwcentry* entries[], unsigned numctrs)
628 int err = -1;
629 err = process_hwcentrylist (entries, numctrs);
630 if (err)
632 TprintfT (DBG_LT0, "hwcfuncs: ERROR: hwcfuncs_bind_hwcentry\n");
633 return err;
635 err = hwcdrv_driver->hwcdrv_create_counters (hwcdef_cnt, hwcdef);
636 return err;
639 /* see hwcfuncs.h */
640 IS_GLOBAL Hwcentry **
641 hwcfuncs_get_ctrs (unsigned *defcnt)
643 if (defcnt)
644 *defcnt = hwcdef_cnt;
645 return hwctable;
648 extern hwcdrv_api_t hwcdrv_pcl_api;
649 static int hwcdrv_driver_inited = 0;
651 hwcdrv_api_t *
652 get_hwcdrv ()
654 if (hwcdrv_driver_inited)
655 return hwcdrv_driver;
656 hwcdrv_driver_inited = 1;
657 cpcN_npics = 0;
658 for (int i = 0; i < MAX_PICS; i++)
659 hwctable[i] = &hwcdef[i];
660 hwcdrv_driver = &hwcdrv_pcl_api;
661 hwcdrv_driver->hwcdrv_init_status = hwcdrv_driver->hwcdrv_init (NULL, NULL);
662 if (hwcdrv_driver->hwcdrv_init_status == 0)
664 hwcdrv_driver->hwcdrv_get_info (NULL, NULL, &cpcN_npics, NULL, NULL);
665 return hwcdrv_driver;
667 hwcdrv_driver = &hwcdrv_default;
668 return hwcdrv_driver;