hwcfuncs.c revision 1.1.1.2 1 1.1.1.2 christos /* Copyright (C) 2021-2024 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 christos hwcf_attr_cb_t *attr_find_action)
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 christos "interval=%d, tag=%u, reg_list=%p\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 christos phwcdef->sort_order, phwcdef->reg_list);
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 christos IS_GLOBAL 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.2 christos
297 1.1 christos /* name */
298 1.1 christos name = dsp;
299 1.1 christos dsp = strchr (dsp, ':');
300 1.1 christos if (dsp == NULL)
301 1.1 christos {
302 1.1 christos err = HWCFUNCS_ERROR_HWCARGS;
303 1.1.1.2 christos break;
304 1.1 christos }
305 1.1 christos *dsp++ = (char) 0;
306 1.1 christos
307 1.1 christos /* int_name */
308 1.1 christos int_name = dsp;
309 1.1 christos dsp = strchr (dsp, ':');
310 1.1 christos if (dsp == NULL)
311 1.1 christos {
312 1.1 christos err = HWCFUNCS_ERROR_HWCARGS;
313 1.1.1.2 christos break;
314 1.1 christos }
315 1.1 christos *dsp++ = (char) 0;
316 1.1 christos
317 1.1 christos /* reg_num */
318 1.1 christos reg = (int) strtol (dsp, &dsp, 0);
319 1.1 christos if (*dsp++ != ':')
320 1.1 christos {
321 1.1 christos err = HWCFUNCS_ERROR_HWCARGS;
322 1.1.1.2 christos break;
323 1.1 christos }
324 1.1 christos if (reg < 0 && reg != -1)
325 1.1 christos {
326 1.1 christos err = HWCFUNCS_ERROR_HWCARGS;
327 1.1.1.2 christos break;
328 1.1 christos }
329 1.1 christos if (reg >= 0)
330 1.1 christos hwcdef[idx].reg_num = reg;
331 1.1 christos
332 1.1 christos /* val */
333 1.1 christos interval = (int) strtol (dsp, &dsp, 0);
334 1.1 christos if (*dsp++ != ':')
335 1.1 christos {
336 1.1 christos err = HWCFUNCS_ERROR_HWCARGS;
337 1.1.1.2 christos break;
338 1.1 christos }
339 1.1 christos if (interval < 0)
340 1.1 christos {
341 1.1 christos err = HWCFUNCS_ERROR_HWCARGS;
342 1.1.1.2 christos break;
343 1.1 christos }
344 1.1 christos hwcdef[idx].val = interval;
345 1.1 christos
346 1.1 christos /* min_time */
347 1.1 christos if (*dsp == 'm')
348 1.1 christos {
349 1.1 christos long long tmp_ll = 0;
350 1.1 christos dsp++;
351 1.1 christos tmp_ll = strtoll (dsp, &dsp, 0);
352 1.1 christos if (*dsp++ != ':')
353 1.1 christos {
354 1.1 christos err = HWCFUNCS_ERROR_HWCARGS;
355 1.1.1.2 christos break;
356 1.1 christos }
357 1.1 christos if (tmp_ll < 0)
358 1.1 christos {
359 1.1 christos err = HWCFUNCS_ERROR_HWCARGS;
360 1.1.1.2 christos break;
361 1.1 christos }
362 1.1 christos hwcdef[idx].min_time = tmp_ll;
363 1.1 christos }
364 1.1 christos else
365 1.1 christos hwcdef[idx].min_time = 0;
366 1.1 christos
367 1.1 christos /* sort_order */
368 1.1 christos sort_order = (int) strtoul (dsp, &dsp, 0);
369 1.1 christos if (*dsp++ != ':')
370 1.1 christos {
371 1.1 christos err = HWCFUNCS_ERROR_HWCARGS;
372 1.1.1.2 christos break;
373 1.1 christos }
374 1.1 christos hwcdef[idx].sort_order = sort_order;
375 1.1 christos
376 1.1 christos /* timecvt */
377 1.1 christos timecvt = (int) strtol (dsp, &dsp, 0);
378 1.1 christos if (*dsp++ != ':')
379 1.1 christos {
380 1.1 christos err = HWCFUNCS_ERROR_HWCARGS;
381 1.1.1.2 christos break;
382 1.1 christos }
383 1.1 christos hwcdef[idx].timecvt = timecvt;
384 1.1 christos
385 1.1 christos /* memop */
386 1.1 christos memop = (ABST_type) strtol (dsp, &dsp, 0);
387 1.1 christos if (*dsp != 0 && *dsp++ != ',')
388 1.1 christos {
389 1.1 christos err = HWCFUNCS_ERROR_HWCARGS;
390 1.1.1.2 christos break;
391 1.1 christos }
392 1.1 christos hwcdef[idx].memop = memop;
393 1.1 christos if (*name)
394 1.1 christos hwcdef[idx].name = strdup (name);
395 1.1 christos else
396 1.1 christos hwcdef[idx].name = strdup (int_name);
397 1.1 christos if (*int_name)
398 1.1 christos hwcdef[idx].int_name = strdup (int_name);
399 1.1 christos else
400 1.1 christos hwcdef[idx].int_name = strdup (name);
401 1.1 christos ctrdefprint (DBG_LT1, "hwcfuncs: process_data_descriptor", &hwcdef[idx]);
402 1.1 christos }
403 1.1 christos
404 1.1 christos if (*dsp)
405 1.1.1.2 christos err = HWCFUNCS_ERROR_HWCARGS;
406 1.1.1.2 christos if (err != 0)
407 1.1.1.2 christos logerr (GTXT ("Data descriptor syntax error near `%s'\n"), dsp);
408 1.1 christos else
409 1.1.1.2 christos hwcdef_cnt = idx;
410 1.1 christos free (ds);
411 1.1 christos return err;
412 1.1 christos }
413 1.1 christos
414 1.1 christos /* initialize hwcdef[] based on user's counter definitions */
415 1.1 christos static int
416 1.1 christos process_hwcentrylist (const Hwcentry* entries[], unsigned numctrs)
417 1.1 christos {
418 1.1 christos int err = 0;
419 1.1 christos clear_hwcdefs ();
420 1.1 christos if (numctrs > cpcN_npics)
421 1.1 christos {
422 1.1 christos logerr (GTXT ("More than %d counters were specified\n"), cpcN_npics); /*!*/
423 1.1 christos return HWCFUNCS_ERROR_HWCARGS;
424 1.1 christos }
425 1.1 christos for (unsigned idx = 0; idx < numctrs; idx++)
426 1.1 christos {
427 1.1 christos Hwcentry *phwcdef = &hwcdef[idx];
428 1.1 christos *phwcdef = *entries[idx];
429 1.1 christos if (phwcdef->name)
430 1.1 christos phwcdef->name = strdup (phwcdef->name);
431 1.1 christos else
432 1.1 christos phwcdef->name = "NULL";
433 1.1 christos if (phwcdef->int_name)
434 1.1 christos phwcdef->int_name = strdup (phwcdef->int_name);
435 1.1 christos else
436 1.1 christos phwcdef->int_name = "NULL";
437 1.1 christos if (phwcdef->val < 0)
438 1.1 christos {
439 1.1 christos logerr (GTXT ("Negative interval specified for HW counter `%s'\n"), /*!*/
440 1.1 christos phwcdef->name);
441 1.1 christos err = HWCFUNCS_ERROR_HWCARGS;
442 1.1 christos break;
443 1.1 christos }
444 1.1 christos ctrdefprint (DBG_LT1, "hwcfuncs: process_hwcentrylist", phwcdef);
445 1.1 christos }
446 1.1 christos if (!err)
447 1.1 christos hwcdef_cnt = numctrs;
448 1.1 christos return err;
449 1.1 christos }
450 1.1 christos
451 1.1 christos /* see hwcfuncs.h */
452 1.1 christos IS_GLOBAL void *
453 1.1 christos hwcfuncs_parse_attrs (const char *countername, hwcfuncs_attr_t attrs[],
454 1.1 christos unsigned max_attrs, uint_t *pnum_attrs, char**errstring)
455 1.1 christos {
456 1.1 christos char *head = NULL;
457 1.1 christos char *tail = NULL;
458 1.1 christos uint_t nattrs = 0;
459 1.1 christos char *counter_copy;
460 1.1 christos int success = 0;
461 1.1 christos char errbuf[512];
462 1.1 christos errbuf[0] = 0;
463 1.1 christos counter_copy = strdup (countername);
464 1.1 christos
465 1.1 christos /* advance pointer to first attribute */
466 1.1 christos tail = strchr (counter_copy, HWCFUNCS_PARSE_ATTR);
467 1.1 christos if (tail)
468 1.1 christos *tail = 0;
469 1.1 christos
470 1.1 christos /* remove regno and value, if supplied */
471 1.1 christos {
472 1.1 christos char *tmp = strchr (counter_copy, HWCFUNCS_PARSE_REGNUM);
473 1.1 christos if (tmp)
474 1.1 christos *tmp = 0;
475 1.1 christos tmp = strchr (counter_copy, HWCFUNCS_PARSE_VALUE);
476 1.1 christos if (tmp)
477 1.1 christos *tmp = 0;
478 1.1 christos }
479 1.1 christos
480 1.1 christos while (tail)
481 1.1 christos {
482 1.1 christos char *pch;
483 1.1 christos if (nattrs >= max_attrs)
484 1.1 christos {
485 1.1 christos snprintf (errbuf, sizeof (errbuf),
486 1.1 christos GTXT ("Too many attributes defined in `%s'"),
487 1.1 christos countername);
488 1.1 christos goto mycpc2_parse_attrs_end;
489 1.1 christos }
490 1.1 christos /* get attribute name */
491 1.1 christos head = tail + 1;
492 1.1 christos tail = strchr (head, HWCFUNCS_PARSE_EQUAL);
493 1.1 christos if (!tail)
494 1.1 christos {
495 1.1 christos snprintf (errbuf, sizeof (errbuf),
496 1.1 christos GTXT ("Missing value for attribute `%s' in `%s'"),
497 1.1 christos head, countername);
498 1.1 christos goto mycpc2_parse_attrs_end;
499 1.1 christos }
500 1.1 christos *tail = 0; /* null terminate current component */
501 1.1 christos attrs[nattrs].ca_name = head;
502 1.1 christos
503 1.1 christos /* get attribute value */
504 1.1 christos head = tail + 1;
505 1.1 christos tail = strchr (head, HWCFUNCS_PARSE_ATTR);
506 1.1 christos if (tail)
507 1.1 christos *tail = 0; /* null terminate current component */
508 1.1 christos attrs[nattrs].ca_val = strtoull (head, &pch, 0);
509 1.1 christos if (pch == head)
510 1.1 christos {
511 1.1 christos snprintf (errbuf, sizeof (errbuf),
512 1.1 christos GTXT ("Illegal value for attribute `%s' in `%s'"),
513 1.1 christos attrs[nattrs].ca_name, countername);
514 1.1 christos goto mycpc2_parse_attrs_end;
515 1.1 christos }
516 1.1 christos TprintfT (DBG_LT0, "hwcfuncs: pic_: '%s', attribute[%u]"
517 1.1 christos " '%s' = 0x%llx\n",
518 1.1 christos counter_copy, nattrs, attrs[nattrs].ca_name,
519 1.1 christos (long long unsigned int) attrs[nattrs].ca_val);
520 1.1 christos
521 1.1 christos nattrs++;
522 1.1 christos }
523 1.1 christos success = 1;
524 1.1 christos
525 1.1 christos mycpc2_parse_attrs_end:
526 1.1 christos *pnum_attrs = nattrs;
527 1.1 christos if (success)
528 1.1 christos {
529 1.1 christos if (errstring)
530 1.1 christos *errstring = NULL;
531 1.1 christos }
532 1.1 christos else
533 1.1 christos {
534 1.1 christos if (errstring)
535 1.1 christos *errstring = strdup (errbuf);
536 1.1 christos free (counter_copy);
537 1.1 christos counter_copy = NULL;
538 1.1 christos }
539 1.1 christos return counter_copy;
540 1.1 christos }
541 1.1 christos
542 1.1 christos IS_GLOBAL void
543 1.1 christos hwcfuncs_parse_ctr (const char *counter_def, int *pplus, char **pnameOnly,
544 1.1 christos char **pattrs, char **pregstr, regno_t *pregno)
545 1.1 christos {
546 1.1 christos char *nameptr, *copy, *slash, *attr_delim;
547 1.1 christos int plus;
548 1.1 christos regno_t regno;
549 1.1 christos nameptr = copy = strdup (counter_def);
550 1.1 christos
551 1.1 christos /* plus */
552 1.1 christos plus = 0;
553 1.1 christos if (nameptr[0] == HWCFUNCS_PARSE_BACKTRACK)
554 1.1 christos {
555 1.1 christos plus = 1;
556 1.1 christos nameptr++;
557 1.1 christos }
558 1.1 christos else if (nameptr[0] == HWCFUNCS_PARSE_BACKTRACK_OFF)
559 1.1 christos {
560 1.1 christos plus = -1;
561 1.1 christos nameptr++;
562 1.1 christos }
563 1.1 christos if (pplus)
564 1.1 christos *pplus = plus;
565 1.1 christos
566 1.1 christos /* regno */
567 1.1 christos regno = REGNO_ANY;
568 1.1 christos if (pregstr)
569 1.1 christos *pregstr = NULL;
570 1.1 christos slash = strchr (nameptr, HWCFUNCS_PARSE_REGNUM);
571 1.1 christos if (slash != NULL)
572 1.1 christos {
573 1.1 christos /* the remaining string should be a number > 0 */
574 1.1 christos if (pregstr)
575 1.1 christos *pregstr = strdup (slash);
576 1.1 christos char *endchar = NULL;
577 1.1 christos regno = (regno_t) strtol (slash + 1, &endchar, 0);
578 1.1 christos if (*endchar != 0)
579 1.1 christos regno = -2;
580 1.1 christos if (*(slash + 1) == '-')
581 1.1 christos regno = -2;
582 1.1 christos /* terminate previous element up to slash */
583 1.1 christos *slash = 0;
584 1.1 christos }
585 1.1 christos if (pregno)
586 1.1 christos *pregno = regno;
587 1.1 christos
588 1.1 christos /* attrs */
589 1.1 christos if (pattrs)
590 1.1 christos *pattrs = NULL;
591 1.1 christos attr_delim = strchr (nameptr, HWCFUNCS_PARSE_ATTR);
592 1.1 christos if (attr_delim != NULL)
593 1.1 christos {
594 1.1 christos if (pattrs)
595 1.1 christos *pattrs = strdup (attr_delim);
596 1.1 christos /* terminate previous element up to attr_delim */
597 1.1 christos *attr_delim++ = 0;
598 1.1 christos }
599 1.1 christos if (pnameOnly)
600 1.1 christos *pnameOnly = strdup (nameptr);
601 1.1 christos free (copy);
602 1.1 christos }
603 1.1 christos
604 1.1 christos /* create counters */
605 1.1 christos IS_GLOBAL int
606 1.1 christos hwcfuncs_bind_descriptor (const char *defstring)
607 1.1 christos {
608 1.1 christos int err = process_data_descriptor (defstring);
609 1.1 christos if (err)
610 1.1 christos {
611 1.1 christos TprintfT (DBG_LT0, "hwcfuncs: ERROR: hwcfuncs_bind_descriptor failed\n");
612 1.1 christos return err;
613 1.1 christos }
614 1.1 christos err = hwcdrv_driver->hwcdrv_create_counters (hwcdef_cnt, hwcdef);
615 1.1 christos return err;
616 1.1 christos }
617 1.1 christos
618 1.1 christos /* see hwcfuncs.h */
619 1.1 christos IS_GLOBAL int
620 1.1 christos hwcfuncs_bind_hwcentry (const Hwcentry* entries[], unsigned numctrs)
621 1.1 christos {
622 1.1 christos int err = -1;
623 1.1 christos err = process_hwcentrylist (entries, numctrs);
624 1.1 christos if (err)
625 1.1 christos {
626 1.1 christos TprintfT (DBG_LT0, "hwcfuncs: ERROR: hwcfuncs_bind_hwcentry\n");
627 1.1 christos return err;
628 1.1 christos }
629 1.1 christos err = hwcdrv_driver->hwcdrv_create_counters (hwcdef_cnt, hwcdef);
630 1.1 christos return err;
631 1.1 christos }
632 1.1 christos
633 1.1 christos /* see hwcfuncs.h */
634 1.1 christos IS_GLOBAL Hwcentry **
635 1.1 christos hwcfuncs_get_ctrs (unsigned *defcnt)
636 1.1 christos {
637 1.1 christos if (defcnt)
638 1.1 christos *defcnt = hwcdef_cnt;
639 1.1 christos return hwctable;
640 1.1 christos }
641 1.1 christos
642 1.1 christos /* return 1 if <regno> is in Hwcentry's list */
643 1.1 christos IS_GLOBAL int
644 1.1 christos regno_is_valid (const Hwcentry * pctr, regno_t regno)
645 1.1 christos {
646 1.1 christos regno_t *reg_list = pctr->reg_list;
647 1.1 christos if (REG_LIST_IS_EMPTY (reg_list))
648 1.1 christos return 0;
649 1.1 christos if (regno == REGNO_ANY) /* wildcard */
650 1.1 christos return 1;
651 1.1 christos for (int ii = 0; ii < MAX_PICS; ii++)
652 1.1 christos {
653 1.1 christos regno_t tmp = reg_list[ii];
654 1.1 christos if (REG_LIST_EOL (tmp)) /* end of list */
655 1.1 christos break;
656 1.1 christos if (tmp == regno) /* is in list */
657 1.1 christos return 1;
658 1.1 christos }
659 1.1 christos return 0;
660 1.1 christos }
661 1.1 christos
662 1.1 christos /* supplied by hwcdrv_api drivers */
663 1.1 christos IS_GLOBAL int
664 1.1 christos hwcfuncs_assign_regnos (Hwcentry* entries[],
665 1.1 christos unsigned numctrs)
666 1.1 christos {
667 1.1 christos if (numctrs > cpcN_npics)
668 1.1 christos {
669 1.1 christos logerr (GTXT ("More than %d counters were specified\n"), cpcN_npics); /*!*/
670 1.1 christos return HWCFUNCS_ERROR_HWCARGS;
671 1.1 christos }
672 1.1 christos return hwcdrv_driver->hwcdrv_assign_regnos (entries, numctrs);
673 1.1 christos }
674 1.1 christos
675 1.1 christos extern hwcdrv_api_t hwcdrv_pcl_api;
676 1.1 christos static int hwcdrv_driver_inited = 0;
677 1.1 christos
678 1.1 christos hwcdrv_api_t *
679 1.1 christos get_hwcdrv ()
680 1.1 christos {
681 1.1 christos if (hwcdrv_driver_inited)
682 1.1 christos return hwcdrv_driver;
683 1.1 christos hwcdrv_driver_inited = 1;
684 1.1 christos cpcN_npics = 0;
685 1.1 christos for (int i = 0; i < MAX_PICS; i++)
686 1.1 christos hwctable[i] = &hwcdef[i];
687 1.1 christos hwcdrv_driver = &hwcdrv_pcl_api;
688 1.1 christos hwcdrv_driver->hwcdrv_init_status = hwcdrv_driver->hwcdrv_init (NULL, NULL);
689 1.1 christos if (hwcdrv_driver->hwcdrv_init_status == 0)
690 1.1 christos {
691 1.1 christos hwcdrv_driver->hwcdrv_get_info (NULL, NULL, &cpcN_npics, NULL, NULL);
692 1.1 christos return hwcdrv_driver;
693 1.1 christos }
694 1.1 christos hwcdrv_driver = &hwcdrv_default;
695 1.1 christos return hwcdrv_driver;
696 1.1 christos }
697