/* Copyright (C) 2021-2024 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/* errmsg buffering is needed only because the most descriptive error
messages from CPC are delivered using a callback mechanism.
hwcfuncs_errmsg_get() should only be used during initialization, and
ideally, only to provide feedback to an end user when his counters can't
be bound to HW.
*/
IS_GLOBAL char *
hwcfuncs_errmsg_get (char *buf, size_t bufsize, int enable)
{
hwcfuncs_errmsg_enabled = 0;
if (buf && bufsize)
{
if (hwcfuncs_errmsg_valid)
{
strncpy (buf, hwcfuncs_errmsg_buf, bufsize);
buf[bufsize - 1] = 0;
}
else
*buf = 0;
}
hwcfuncs_errmsg_buf[0] = 0;
hwcfuncs_errmsg_valid = 0;
hwcfuncs_errmsg_enabled = enable;
return buf;
}
/* used by cpc to log an error */
IS_GLOBAL void
hwcfuncs_int_capture_errmsg (const char *fn, int subcode,
const char *fmt, va_list ap)
{
if (hwcfuncs_errmsg_enabled &&
!hwcfuncs_errmsg_valid)
{
vsnprintf (hwcfuncs_errmsg_buf, sizeof (hwcfuncs_errmsg_buf), fmt, ap);
TprintfT (DBG_LT0, "hwcfuncs: cpcN_capture_errmsg(): %s\n",
hwcfuncs_errmsg_buf);
hwcfuncs_errmsg_valid = 1;
}
return;
}
/* Log an internal error to the CPC error buffer.
* Note: only call this during init functions.
* Note: when most cpc calls fail, they will call cpcN_capture_errmsg()
* directly, so only call logerr() when a non-cpc function fails.
*/
IS_GLOBAL void
hwcfuncs_int_logerr (const char *format, ...)
{
va_list va;
va_start (va, format);
hwcfuncs_int_capture_errmsg ("logerr", 0, format, va);
va_end (va);
}
/* initialize hwcdef[] based on user's counter definitions */
static int
process_data_descriptor (const char *defstring)
{
/*
* <defstring> format should be of format
* :%s:%s:0x%x:%d:%lld:%d:%d:0x%x[,%s...repeat for each ctr]
* where the counter fields are:
* :<userName>:<internalCtr>:<register>:<timeoutVal>[:m<min_time>]:<tag>:<timecvt>:<memop>
* See Coll_Ctrl::build_data_desc().
*/
int err = 0;
char *ds = NULL;
char *dsp = NULL;
unsigned idx;
/* plus */
plus = 0;
if (nameptr[0] == HWCFUNCS_PARSE_BACKTRACK)
{
plus = 1;
nameptr++;
}
else if (nameptr[0] == HWCFUNCS_PARSE_BACKTRACK_OFF)
{
plus = -1;
nameptr++;
}
if (pplus)
*pplus = plus;
/* regno */
regno = REGNO_ANY;
if (pregstr)
*pregstr = NULL;
slash = strchr (nameptr, HWCFUNCS_PARSE_REGNUM);
if (slash != NULL)
{
/* the remaining string should be a number > 0 */
if (pregstr)
*pregstr = strdup (slash);
char *endchar = NULL;
regno = (regno_t) strtol (slash + 1, &endchar, 0);
if (*endchar != 0)
regno = -2;
if (*(slash + 1) == '-')
regno = -2;
/* terminate previous element up to slash */
*slash = 0;
}
if (pregno)
*pregno = regno;
/* attrs */
if (pattrs)
*pattrs = NULL;
attr_delim = strchr (nameptr, HWCFUNCS_PARSE_ATTR);
if (attr_delim != NULL)
{
if (pattrs)
*pattrs = strdup (attr_delim);
/* terminate previous element up to attr_delim */
*attr_delim++ = 0;
}
if (pnameOnly)
*pnameOnly = strdup (nameptr);
free (copy);
}
/* see hwcfuncs.h */
IS_GLOBAL Hwcentry **
hwcfuncs_get_ctrs (unsigned *defcnt)
{
if (defcnt)
*defcnt = hwcdef_cnt;
return hwctable;
}
/* return 1 if <regno> is in Hwcentry's list */
IS_GLOBAL int
regno_is_valid (const Hwcentry * pctr, regno_t regno)
{
regno_t *reg_list = pctr->reg_list;
if (REG_LIST_IS_EMPTY (reg_list))
return 0;
if (regno == REGNO_ANY) /* wildcard */
return 1;
for (int ii = 0; ii < MAX_PICS; ii++)
{
regno_t tmp = reg_list[ii];
if (REG_LIST_EOL (tmp)) /* end of list */
break;
if (tmp == regno) /* is in list */
return 1;
}
return 0;
}
/* supplied by hwcdrv_api drivers */
IS_GLOBAL int
hwcfuncs_assign_regnos (Hwcentry* entries[],
unsigned numctrs)
{
if (numctrs > cpcN_npics)
{
logerr (GTXT ("More than %d counters were specified\n"), cpcN_npics); /*!*/
return HWCFUNCS_ERROR_HWCARGS;
}
return hwcdrv_driver->hwcdrv_assign_regnos (entries, numctrs);
}
extern hwcdrv_api_t hwcdrv_pcl_api;
static int hwcdrv_driver_inited = 0;