diff options
Diffstat (limited to 'gprofng/src/Settings.cc')
-rw-r--r-- | gprofng/src/Settings.cc | 1586 |
1 files changed, 1586 insertions, 0 deletions
diff --git a/gprofng/src/Settings.cc b/gprofng/src/Settings.cc new file mode 100644 index 00000000000..965b9174da6 --- /dev/null +++ b/gprofng/src/Settings.cc @@ -0,0 +1,1586 @@ +/* Copyright (C) 2021 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. */ + +#include "config.h" +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/param.h> + +#include "enums.h" +#include "Settings.h" +#include "DbeSession.h" +#include "Command.h" +#include "Application.h" +#include "MemorySpace.h" +#include "StringBuilder.h" +#include "Table.h" +#include "Emsg.h" +#include "util.h" +#include "i18n.h" + +// Commands for compiler commentary +static const char *comp_cmd[] = { + NTXT ("basic"), + NTXT ("version"), + NTXT ("warn"), + NTXT ("parallel"), + NTXT ("query"), + NTXT ("loop"), + NTXT ("pipe"), + NTXT ("inline"), + NTXT ("memops"), + NTXT ("fe"), + NTXT ("codegen"), + NTXT ("src"), + NTXT ("asrc"), + NTXT ("nosrc"), + NTXT ("hex"), + NTXT ("nohex"), + NTXT ("threshold"), + NTXT ("cf") +}; + +static const int comp_vis[] = { + CCMV_BASIC, + CCMV_VER, + CCMV_WARN, + CCMV_PAR, + CCMV_QUERY, + CCMV_LOOP, + CCMV_PIPE, + CCMV_INLINE, + CCMV_MEMOPS, + CCMV_FE, + CCMV_CG, + COMP_SRC, + COMP_SRC_METRIC, + COMP_NOSRC, + COMP_HEX, + COMP_NOHEX, + COMP_THRESHOLD, + COMP_CMPLINE +}; + +const int comp_size = sizeof (comp_cmd) / sizeof (char *); + +// Commands for timeline +typedef enum +{ + TLCMD_INVALID, + TLCMD_ENTITY_MODE, + TLCMD_ALIGN, + TLCMD_DEPTH +} TLModeSubcommand; + +typedef struct +{ + const char * cmdText; + TLModeSubcommand cmdType; + int cmdId; +} TLModeCmd; +static const TLModeCmd tlmode_cmd[] = { + // MODE commands + {NTXT ("lwp"), TLCMD_ENTITY_MODE, PROP_LWPID}, + {NTXT ("thread"), TLCMD_ENTITY_MODE, PROP_THRID}, + {NTXT ("cpu"), TLCMD_ENTITY_MODE, PROP_CPUID}, + {NTXT ("experiment"), TLCMD_ENTITY_MODE, PROP_EXPID}, + // ALIGN commands + {NTXT ("root"), TLCMD_ALIGN, TLSTACK_ALIGN_ROOT}, + {NTXT ("leaf"), TLCMD_ALIGN, TLSTACK_ALIGN_LEAF}, + // DEPTH commands + {NTXT ("depth"), TLCMD_DEPTH, 0 /* don't care */} +}; + +static const int tlmode_size = sizeof (tlmode_cmd) / sizeof (TLModeCmd); + +// Constructor + +Settings::Settings (Application *_app) +{ + // Remember the application + app = _app; + + // Clear all default strings + str_vmode = NULL; + str_en_desc = NULL; + str_datamode = NULL; + str_scompcom = NULL; + str_sthresh = NULL; + str_dcompcom = NULL; + str_dthresh = NULL; + str_dmetrics = NULL; + str_dsort = NULL; + str_tlmode = NULL; + str_tldata = NULL; + str_tabs = NULL; + str_rtabs = NULL; + str_search_path = NULL; + str_name_format = NULL; + str_limit = NULL; + str_printmode = NULL; + str_compare = NULL; + preload_libdirs = NULL; + pathmaps = new Vector<pathmap_t*>; + lo_expands = new Vector<lo_expand_t*>; + lo_expand_default = LIBEX_SHOW; + is_loexpand_default = true; + tabs_processed = false; + + // set default-default values + name_format = Histable::NA; + view_mode = VMODE_USER; + en_desc = false; + en_desc_cmp = NULL; + en_desc_usr = NULL; + src_compcom = 2147483647; + dis_compcom = 2147483647; +#define DEFAULT_SRC_DIS_THRESHOLD 75 + threshold_src = DEFAULT_SRC_DIS_THRESHOLD; + threshold_dis = DEFAULT_SRC_DIS_THRESHOLD; + src_visible = true; + srcmetric_visible = false; + hex_visible = false; + cmpline_visible = true; + funcline_visible = true; + tldata = NULL; + tlmode = 0; + stack_align = 0; + stack_depth = 0; + limit = 0; + // print mode is initialized after the .rc files are read + print_delim = ','; + compare_mode = CMP_DISABLE; + machinemodel = NULL; + ignore_no_xhwcprof = false; + ignore_fs_warn = false; + + // construct the master list of tabs + buildMasterTabList (); + + indx_tab_state = new Vector<bool>; + indx_tab_order = new Vector<int>; + mem_tab_state = new Vector<bool>; + mem_tab_order = new Vector<int>; + + // note that the .rc files are not read here, but later +} + +// Constructor for duplicating an existing Settings class + +Settings::Settings (Settings * _settings) +{ + int index; + app = _settings->app; + + // Copy all default strings + str_vmode = dbe_strdup (_settings->str_vmode); + str_en_desc = dbe_strdup (_settings->str_en_desc); + str_datamode = dbe_strdup (_settings->str_datamode); + str_scompcom = dbe_strdup (_settings->str_scompcom); + str_sthresh = dbe_strdup (_settings->str_sthresh); + str_dcompcom = dbe_strdup (_settings->str_dcompcom); + str_dthresh = dbe_strdup (_settings->str_dthresh); + str_dmetrics = dbe_strdup (_settings->str_dmetrics); + str_dsort = dbe_strdup (_settings->str_dsort); + str_tlmode = dbe_strdup (_settings->str_tlmode); + str_tldata = dbe_strdup (_settings->str_tldata); + str_tabs = dbe_strdup (_settings->str_tabs); + str_rtabs = dbe_strdup (_settings->str_rtabs); + str_search_path = dbe_strdup (_settings->str_search_path); + str_name_format = dbe_strdup (_settings->str_name_format); + str_limit = dbe_strdup (_settings->str_limit); + str_printmode = dbe_strdup (_settings->str_printmode); + str_compare = dbe_strdup (_settings->str_compare); + preload_libdirs = dbe_strdup (_settings->preload_libdirs); + + // replicate the pathmap vector + pathmap_t *thismap; + pathmap_t *newmap; + pathmaps = new Vector<pathmap_t*>; + + Vec_loop (pathmap_t*, _settings->pathmaps, index, thismap) + { + newmap = new pathmap_t; + newmap->old_prefix = dbe_strdup (thismap->old_prefix); + newmap->new_prefix = dbe_strdup (thismap->new_prefix); + pathmaps->append (newmap); + } + + // replicate the lo_expand vector and default + lo_expand_t *this_lo_ex; + lo_expand_t *new_lo_ex; + lo_expand_default = _settings->lo_expand_default; + is_loexpand_default = _settings->is_loexpand_default; + lo_expands = new Vector<lo_expand_t*>; + + Vec_loop (lo_expand_t*, _settings->lo_expands, index, this_lo_ex) + { + new_lo_ex = new lo_expand_t; + new_lo_ex->libname = dbe_strdup (this_lo_ex->libname); + new_lo_ex->expand = this_lo_ex->expand; + lo_expands->append (new_lo_ex); + } + tabs_processed = _settings->tabs_processed; + + // Copy the various values from the _settings instance + name_format = _settings->name_format; + view_mode = _settings->view_mode; + en_desc = false; + en_desc_cmp = NULL; + en_desc_usr = NULL; + if (_settings->en_desc_usr) + set_en_desc (_settings->en_desc_usr, true); + src_compcom = _settings->src_compcom; + dis_compcom = _settings->dis_compcom; + threshold_src = _settings->threshold_src; + threshold_dis = _settings->threshold_dis; + src_visible = _settings->src_visible; + srcmetric_visible = _settings->srcmetric_visible; + hex_visible = _settings->hex_visible; + cmpline_visible = _settings->cmpline_visible; + funcline_visible = _settings->funcline_visible; + tldata = dbe_strdup (_settings->tldata); + tlmode = _settings->tlmode; + stack_align = _settings->stack_align; + stack_depth = _settings->stack_depth; + limit = _settings->limit; + print_mode = _settings->print_mode; + print_delim = _settings->print_delim; + compare_mode = _settings->compare_mode; + machinemodel = dbe_strdup (_settings->machinemodel); + ignore_no_xhwcprof = _settings->ignore_no_xhwcprof; + ignore_fs_warn = _settings->ignore_fs_warn; + + // copy the tab list, too + tab_list = new Vector<DispTab*>; + DispTab *dsptab; + + Vec_loop (DispTab*, _settings->tab_list, index, dsptab) + { + DispTab *ntab; + ntab = new DispTab (dsptab->type, dsptab->order, dsptab->visible, dsptab->cmdtoken); + ntab->setAvailability (dsptab->available); + tab_list->append (ntab); + } + + // construct the master list of memory tabs & copy order + index = _settings->mem_tab_state->size (); + mem_tab_state = new Vector<bool>(index); + mem_tab_order = new Vector<int>(index); + for (int i = 0; i < index; i++) + { + mem_tab_state->append (false); + mem_tab_order->append (_settings->mem_tab_order->fetch (i)); + } + + // construct the master list of index tabs & copy order + index = _settings->indx_tab_state->size (); + indx_tab_state = new Vector<bool>(index); + indx_tab_order = new Vector<int>(index); + for (int i = 0; i < index; i++) + indx_tab_order->append (_settings->indx_tab_order->fetch (i)); + set_IndxTabState (_settings->indx_tab_state); +} + +Settings::~Settings () +{ + for (int i = 0; i < pathmaps->size (); ++i) + { + pathmap_t *pmap = pathmaps->fetch (i); + free (pmap->old_prefix); + free (pmap->new_prefix); + delete pmap; + } + delete pathmaps; + + for (int i = 0; i < lo_expands->size (); ++i) + { + lo_expand_t *lo_ex = lo_expands->fetch (i); + free (lo_ex->libname); + delete lo_ex; + } + delete lo_expands; + + tab_list->destroy (); + delete tab_list; + delete indx_tab_state; + delete indx_tab_order; + delete mem_tab_state; + delete mem_tab_order; + + free (str_vmode); + free (str_en_desc); + free (str_datamode); + free (str_scompcom); + free (str_sthresh); + free (str_dcompcom); + free (str_dthresh); + free (str_dmetrics); + free (str_dsort); + free (str_tlmode); + free (str_tldata); + free (str_tabs); + free (str_rtabs); + free (str_search_path); + free (str_name_format); + free (str_limit); + free (str_compare); + free (str_printmode); + free (preload_libdirs); + free (tldata); + free (en_desc_usr); + if (en_desc_cmp) + { + regfree (en_desc_cmp); + delete en_desc_cmp; + } +} + +/** + * Read .er.rc file from the specified location + * @param path + * @return + */ +char * +Settings::read_rc (char *path) +{ + StringBuilder sb; + Emsgqueue *commentq = new Emsgqueue (NTXT ("setting_commentq")); + + // Check file name + if (NULL == path) + return dbe_strdup (GTXT ("Error: empty file name")); + bool override = true; + set_rc (path, true, commentq, override); + Emsg *msg = commentq->fetch (); + while (msg != NULL) + { + char *str = msg->get_msg (); + sb.append (str); + msg = msg->next; + } + return sb.toString (); +} + +void +Settings::read_rc (bool ipc_or_rdt_mode) +{ + bool override = false; + + // Read file from the current working directory + char *rc_path = realpath (NTXT ("./.gprofng.rc"), NULL); + if (rc_path) + set_rc (rc_path, true, app->get_comments_queue (), override, ipc_or_rdt_mode); + + // Read file from the user's home directory + char *home = getenv (NTXT ("HOME")); + if (home) + { + char *strbuf = dbe_sprintf (NTXT ("%s/.gprofng.rc"), home); + char *home_rc_path = realpath (strbuf, NULL); + if (home_rc_path) + { + if (rc_path == NULL || strcmp (rc_path, home_rc_path) != 0) + set_rc (home_rc_path, true, app->get_comments_queue (), override, ipc_or_rdt_mode); + free (home_rc_path); + } + free (strbuf); + } + free (rc_path); + + // Read system-wide file + rc_path = dbe_sprintf (NTXT ("%s/../etc/gprofng.rc"), app->get_run_dir ()); + if (access (rc_path, R_OK | F_OK) != 0) + { + StringBuilder sb; + sb.sprintf (GTXT ("Warning: Default gprofng.rc file (%s) missing; configuration error "), rc_path); + Emsg *m = new Emsg (CMSG_COMMENT, sb); + app->get_comments_queue ()->append (m); + } + else + set_rc (rc_path, false, app->get_comments_queue (), override); + free (rc_path); + is_loexpand_default = true; + if (str_printmode == NULL) + { + // only if there's none set + print_mode = PM_TEXT; + str_printmode = dbe_strdup (NTXT ("text")); + } +} + + +// Handle various settings from reading the name .rc file +// This function is called for each .rc file read, and, for +// some settings, it accumulates the strings from the files. +// For others, it accepts the first appearance for a setting in a +// .rc file, and ignores subsequent appearances from other files. +// Error messages are appended to the Emsgqueue specified by the caller + +#define MAXARGS 20 + +void +Settings::set_rc (const char *path, bool msg, Emsgqueue *commentq, + bool override, bool ipc_or_rdt_mode) +{ + CmdType cmd_type; + int arg_count, cparam; + char *cmd, *end_cmd, *strbuf; + char *arglist[MAXARGS]; + StringBuilder sb; + + FILE *fptr = fopen (path, NTXT ("r")); + if (fptr == NULL) + return; + + if (msg) + { + sb.sprintf (GTXT ("Processed %s for default settings"), path); + Emsg *m = new Emsg (CMSG_COMMENT, sb); + commentq->append (m); + } + int line_no = 0; + end_cmd = NULL; + while (!feof (fptr)) + { + char *script = read_line (fptr); + if (script == NULL) + continue; + line_no++; + strtok (script, NTXT ("\n")); + + // extract the command + cmd = strtok (script, NTXT (" \t")); + if (cmd == NULL || *cmd == '#' || *cmd == '\n') + { + free (script); + continue; + } + char *remainder = strtok (NULL, NTXT ("\n")); + // now extract the arguments + int nargs = 0; + for (;;) + { + if (nargs >= MAXARGS) + { + if (!msg) + { + msg = true; // suppress repeats of header + Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings")); + commentq->append (m); + } + sb.sprintf (GTXT ("Warning: more than %d arguments to %s command, line %d\n"), + MAXARGS, cmd, line_no); + Emsg *m = new Emsg (CMSG_COMMENT, sb); + commentq->append (m); + break; + } + + char *nextarg = strtok (remainder, NTXT ("\n")); + if (nextarg == NULL || *nextarg == '#') + break; + arglist[nargs++] = parse_qstring (nextarg, &end_cmd); + remainder = end_cmd; + if (remainder == NULL) + break; + // skip any blanks or tabs to get to next argument + while (*remainder == ' ' || *remainder == '\t') + remainder++; + } + cmd_type = Command::get_command (cmd, arg_count, cparam); + // check for extra arguments + if ((cmd_type != UNKNOWN_CMD && cmd_type != INDXOBJDEF) && (nargs > arg_count)) + { + if (!msg) + { + msg = true; // suppress repeats of header + Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings")); + commentq->append (m); + } + sb.sprintf (GTXT ("Warning: extra arguments to %s command, line %d\n"), cmd, line_no); + Emsg *m = new Emsg (CMSG_COMMENT, sb); + commentq->append (m); + } + if (nargs < arg_count) + { + if (!msg) + { + msg = true; // suppress repeats of header + Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings")); + commentq->append (m); + } + sb.sprintf (GTXT ("Error: missing arguments to %s command, line %d\n"), + cmd, line_no); + Emsg *m = new Emsg (CMSG_COMMENT, sb); + commentq->append (m); + + // ignore this command + free (script); + continue; + } + if (ipc_or_rdt_mode && (cmd_type != ADDPATH) && (cmd_type != PATHMAP)) + { + free (script); + continue; + } + switch (cmd_type) + { + case SCOMPCOM: + if (!str_scompcom || override) + { + str_scompcom = dbe_strdup (arglist[0]); + proc_compcom (arglist[0], true, true); + } + break; + case STHRESH: + if (!str_sthresh || override) + { + str_sthresh = dbe_strdup (arglist[0]); + proc_thresh (arglist[0], true, true); + break; + } + break; + case DCOMPCOM: + if (!str_dcompcom || override) + { + str_dcompcom = dbe_strdup (arglist[0]); + proc_compcom (arglist[0], false, true); + } + break; + case COMPCOM: + // process as if it were for both source and disassembly + // note that if it is set, subsequent SCOMPCOM and DCOMPCOM + // will be ignored + if (!str_scompcom || override) + { + str_scompcom = dbe_strdup (arglist[0]); + proc_compcom (arglist[0], true, true); + } + if (!str_dcompcom || override) + { + str_dcompcom = dbe_strdup (arglist[0]); + proc_compcom (arglist[0], false, true); + } + break; + case DTHRESH: + if (!str_dthresh || override) + { + str_dthresh = dbe_strdup (arglist[0]); + proc_thresh (arglist[0], false, true); + } + break; + case DMETRICS: + // append new settings to old, if necessary + if (str_dmetrics) + { + char *name = strstr (str_dmetrics, ":name"); + if (name == NULL) + strbuf = dbe_sprintf ("%s:%s", str_dmetrics, arglist[0]); + else + { + char * next = strstr (name + 1, ":"); + if (next == NULL) + { + name[0] = '\0'; + strbuf = dbe_sprintf ("%s:%s:name", str_dmetrics, arglist[0]); + } + else + strbuf = dbe_sprintf ("%s:%s", str_dmetrics, arglist[0]); + } + free (str_dmetrics); + str_dmetrics = strbuf; + } + else + str_dmetrics = dbe_strdup (arglist[0]); + break; + case DSORT: + // append new settings to old, if necessary + if (str_dsort) + { + strbuf = dbe_sprintf (NTXT ("%s:%s"), str_dsort, arglist[0]); + free (str_dsort); + str_dsort = strbuf; + } + else + str_dsort = dbe_strdup (arglist[0]); + break; + case TLMODE: + if (!str_tlmode || override) + { + str_tlmode = dbe_strdup (arglist[0]); + proc_tlmode (arglist[0], true); + } + break; + case TLDATA: + if (!str_tldata || override) + { + str_tldata = dbe_strdup (arglist[0]); + proc_tldata (arglist[0], true); + } + break; + case TABS: + if (!str_tabs || override) + // the string is processed later, after all .rc files are read + str_tabs = dbe_strdup (arglist[0]); + break; + case RTABS: + if (!str_rtabs || override) + // the string is processed later, after all .rc files are read + str_rtabs = dbe_strdup (arglist[0]); + break; + case ADDPATH: + if (str_search_path) + { + strbuf = dbe_sprintf (NTXT ("%s:%s"), str_search_path, arglist[0]); + free (str_search_path); + str_search_path = strbuf; + } + else + str_search_path = dbe_strdup (arglist[0]); + break; + case PATHMAP: + { + char *err = add_pathmap (pathmaps, arglist[0], arglist[1]); + free (err); // XXX error is not reported + break; + } + case LIBDIRS: + if (preload_libdirs == NULL) + preload_libdirs = dbe_strdup (arglist[0]); + break; + case NAMEFMT: + if (name_format == Histable::NA) + set_name_format (arglist[0]); + break; + case VIEWMODE: + if (!str_vmode || override) + { + str_vmode = dbe_strdup (arglist[0]); + set_view_mode (arglist[0], true); + } + break; + case EN_DESC: + if (!str_en_desc || override) + { + str_en_desc = dbe_strdup (arglist[0]); + set_en_desc (arglist[0], true); + } + break; + case LIMIT: + if (!str_limit || override) + { + str_limit = dbe_strdup (arglist[0]); + set_limit (arglist[0], true); + } + break; + case PRINTMODE: + if (!str_printmode || override) + set_printmode (arglist[0]); + break; + case COMPARE: + if (!str_compare || override) + { + char *s = arglist[0]; + if (s) + str_compare = dbe_strdup (s); + else + s = NTXT (""); + if (strcasecmp (s, NTXT ("OFF")) == 0 + || strcmp (s, NTXT ("0")) == 0) + set_compare_mode (CMP_DISABLE); + else if (strcasecmp (s, NTXT ("ON")) == 0 + || strcmp (s, NTXT ("1")) == 0) + set_compare_mode (CMP_ENABLE); + else if (strcasecmp (s, NTXT ("DELTA")) == 0) + set_compare_mode (CMP_DELTA); + else if (strcasecmp (s, NTXT ("RATIO")) == 0) + set_compare_mode (CMP_RATIO); + else + { + sb.sprintf (GTXT (" .er.rc:%d The argument of 'compare' should be 'on', 'off', 'delta', or 'ratio'"), + (int) line_no); + Emsg *m = new Emsg (CMSG_COMMENT, sb); + commentq->append (m); + } + } + break; + + case INDXOBJDEF: + { + char *ret = dbeSession->indxobj_define (arglist[0], NULL, arglist[1], (nargs >= 3) ? PTXT (arglist[2]) : NULL, (nargs >= 4) ? PTXT (arglist[3]) : NULL); + if (ret != NULL) + { + sb.sprintf (GTXT (" %s: line %d `%s %s %s'\n"), + ret, line_no, cmd, arglist[0], arglist[1]); + Emsg *m = new Emsg (CMSG_COMMENT, sb); + commentq->append (m); + } + break; + } +#ifdef sparc + //XXX: should be conditional on the experiment ARCH, not dbe ARCH + case IGNORE_NO_XHWCPROF: + // ignore absence of -xhwcprof info for dataspace profiling + set_ignore_no_xhwcprof (true); + break; +#endif // sparc + case IGNORE_FS_WARN: + // ignore file system warning in experiments + set_ignore_fs_warn (true); + break; + case OBJECT_SHOW: + // Add the named libraries to the lib_expands array + set_libexpand (arglist[0], LIBEX_SHOW, true); + break; + case OBJECT_HIDE: + // Add the named libraries to the lib_expands array + set_libexpand (arglist[0], LIBEX_HIDE, true); + break; + case OBJECT_API: + // Add the named libraries to the lib_expands array + set_libexpand (arglist[0], LIBEX_API, true); + break; + case COMMENT: + // ignore the line + break; + default: + { + // unexpected command in an rc file + if (!msg) + { + // if quiet, can remain so no longer + msg = true; + Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings")); + commentq->append (m); + } + sb.sprintf (GTXT (" Unrecognized .gprofng.rc command on line %d: `%.64s'"), + line_no, cmd); + Emsg *m = new Emsg (CMSG_COMMENT, sb); + commentq->append (m); + break; + } + } + free (script); + } + fclose (fptr); +} + +Cmd_status +Settings::set_view_mode (char *arg, bool rc) +{ + if (!strcasecmp (arg, NTXT ("user"))) + view_mode = VMODE_USER; + else if (!strcasecmp (arg, NTXT ("expert"))) + view_mode = VMODE_EXPERT; + else if (!strcasecmp (arg, NTXT ("machine"))) + view_mode = VMODE_MACHINE; + else if (!rc) + return CMD_BAD_ARG; + return CMD_OK; +} + +Cmd_status +Settings::set_en_desc (char *arg, bool rc) +{ + regex_t *regex_desc = NULL; + + // cases below should be similar to Coll_Ctrl::set_follow_mode() cases + if (!strcasecmp (arg, NTXT ("on"))) + en_desc = true; + else if (!strcasecmp (arg, NTXT ("off"))) + en_desc = false; + else if (arg[0] == '=' && arg[1] != 0) + { + // user has specified a string matching specification + int ercode; + { // compile regex_desc + char * str = dbe_sprintf (NTXT ("^%s$"), arg + 1); + regex_desc = new regex_t; + memset (regex_desc, 0, sizeof (regex_t)); + ercode = regcomp (regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE); + free (str); + } + if (ercode) + { + // syntax error in parsing string + delete regex_desc; + if (!rc) + return CMD_BAD_ARG; + return CMD_OK; + } + en_desc = true; + } + else + { + if (!rc) + return CMD_BAD_ARG; + return CMD_OK; + } + free (en_desc_usr); + en_desc_usr = dbe_strdup (arg); + if (en_desc_cmp) + { + regfree (en_desc_cmp); + delete en_desc_cmp; + } + en_desc_cmp = regex_desc; + return CMD_OK; +} + +// See if a descendant matches either the lineage or the executable name +bool +Settings::check_en_desc (const char *lineage, const char *targname) +{ + bool rc; + if (en_desc_cmp == NULL) + return en_desc; // no specification was set, use the binary on/off value + if (lineage == NULL) // user doesn't care about specification + return en_desc; // use the binary on/off specification + if (!regexec (en_desc_cmp, lineage, 0, NULL, 0)) + rc = true; // this one matches user specification + else if (targname == NULL) + rc = false; //a NULL name does not match any expression + else if (!regexec (en_desc_cmp, targname, 0, NULL, 0)) + rc = true; // this one matches the executable name + else + rc = false; + return rc; +} + +char * +Settings::set_limit (char *arg, bool) +{ + limit = (int) strtol (arg, (char **) NULL, 10); + return NULL; +} + +char * +Settings::set_printmode (char *arg) +{ + if (arg == NULL) + return dbe_sprintf (GTXT ("The argument to '%s' must be '%s' or '%s' or a single-character"), + NTXT ("printmode"), NTXT ("text"), NTXT ("html")); + if (strlen (arg) == 1) + { + print_mode = PM_DELIM_SEP_LIST; + print_delim = arg[0]; + } + else if (!strcasecmp (arg, NTXT ("text"))) + print_mode = PM_TEXT; + else if (!strcasecmp (arg, NTXT ("html"))) + print_mode = PM_HTML; + else + return dbe_sprintf (GTXT ("The argument to '%s' must be '%s' or '%s' or a single-character"), + NTXT ("printmode"), NTXT ("text"), NTXT ("html")); + free (str_printmode); + str_printmode = dbe_strdup (arg); + return NULL; +} + +Cmd_status +Settings::proc_compcom (const char *cmd, bool isSrc, bool rc) +{ + int ck_compcom_bits, ck_threshold; + bool ck_hex_visible = false; + bool ck_src_visible = false; + bool ck_srcmetric_visible = false; + bool got_compcom_bits, got_threshold, got_src_visible, got_srcmetric_visible; + bool got_hex_visible, got; + int len, i; + char *mcmd, *param; + int flag, value = 0; + Cmd_status status; + char buf[BUFSIZ], *list; + + if (cmd == NULL) + return CMD_BAD; + ck_compcom_bits = 0; + ck_threshold = 0; + got_compcom_bits = got_threshold = got_src_visible = false; + got_srcmetric_visible = got_hex_visible = false; + snprintf (buf, sizeof (buf), NTXT ("%s"), cmd); + list = buf; + while ((mcmd = strtok (list, NTXT (":"))) != NULL) + { + list = NULL; + // if "all" or "none" + if (!strcasecmp (mcmd, Command::ALL_CMD)) + { + got_compcom_bits = true; + ck_compcom_bits = CCMV_ALL; + continue; + } + else if (!strcasecmp (mcmd, Command::NONE_CMD)) + { + got_compcom_bits = true; + ck_compcom_bits = 0; + continue; + } + + // Find parameter after '=' + param = strchr (mcmd, '='); + if (param) + { + *param = '\0'; + param++; + } + status = CMD_OK; + got = false; + flag = 0; + len = (int) strlen (mcmd); + for (i = 0; status == CMD_OK && i < comp_size; i++) + if (!strncasecmp (mcmd, comp_cmd[i], len)) + { + if (got) // Ambiguous comp_com command + status = CMD_AMBIGUOUS; + else + { + got = true; + flag = comp_vis[i]; + // Check argument + if (flag == COMP_THRESHOLD) + { + if (param == NULL) + status = CMD_BAD_ARG; + else + { + value = (int) strtol (param, ¶m, 10); + if (value < 0 || value > 100) + status = CMD_OUTRANGE; + } + } + else if (param != NULL) + status = CMD_BAD_ARG; + } + } + + // Not valid comp_com command + if (!got) + status = CMD_INVALID; + if (status != CMD_OK) + { + if (!rc) + return status; + continue; + } + + // Set bits + switch (flag) + { + case COMP_CMPLINE: + cmpline_visible = true; + break; + case COMP_FUNCLINE: + funcline_visible = true; + break; + case COMP_THRESHOLD: + got_threshold = true; + ck_threshold = value; + break; + case COMP_SRC: + got_src_visible = true; + ck_src_visible = true; + break; + case COMP_SRC_METRIC: + got_srcmetric_visible = true; + ck_srcmetric_visible = true; + got_src_visible = true; + ck_src_visible = true; + break; + case COMP_NOSRC: + got_src_visible = true; + ck_src_visible = false; + break; + case COMP_HEX: + got_hex_visible = true; + ck_hex_visible = true; + break; + case COMP_NOHEX: + got_hex_visible = true; + ck_hex_visible = false; + break; + case CCMV_BASIC: + got_compcom_bits = true; + ck_compcom_bits = CCMV_BASIC; + break; + default: + got_compcom_bits = true; + ck_compcom_bits |= flag; + } + } + + // No error, update + if (got_compcom_bits) + { + if (isSrc) + src_compcom = ck_compcom_bits; + else + dis_compcom = ck_compcom_bits; + } + if (got_threshold) + { + if (isSrc) + threshold_src = ck_threshold; + else + threshold_dis = ck_threshold; + } + if (got_src_visible) + src_visible = ck_src_visible; + if (got_srcmetric_visible) + srcmetric_visible = ck_srcmetric_visible; + if (got_hex_visible) + hex_visible = ck_hex_visible; + return CMD_OK; +} + +// Process a threshold setting +Cmd_status +Settings::proc_thresh (char *cmd, bool isSrc, bool rc) +{ + int value; + if (cmd == NULL) + value = DEFAULT_SRC_DIS_THRESHOLD; // the default + else + value = (int) strtol (cmd, &cmd, 10); + if (value < 0 || value > 100) + { + if (!rc) + return CMD_OUTRANGE; + value = DEFAULT_SRC_DIS_THRESHOLD; + } + if (isSrc) + threshold_src = value; + else + threshold_dis = value; + return CMD_OK; +} + +// return any error string from processing visibility settings +char * +Settings::get_compcom_errstr (Cmd_status status, const char *cmd) +{ + int i; + StringBuilder sb; + switch (status) + { + case CMD_BAD: + sb.append (GTXT ("No commentary classes has been specified.")); + break; + case CMD_AMBIGUOUS: + sb.append (GTXT ("Ambiguous commentary classes: ")); + break; + case CMD_BAD_ARG: + sb.append (GTXT ("Invalid argument for commentary classes: ")); + break; + case CMD_OUTRANGE: + sb.append (GTXT ("Out of range commentary classes argument: ")); + break; + case CMD_INVALID: + sb.append (GTXT ("Invalid commentary classes: ")); + break; + case CMD_OK: + break; + } + if (cmd) + sb.append (cmd); + sb.append (GTXT ("\nAvailable commentary classes: ")); + for (i = 0; i < comp_size; i++) + { + sb.append (comp_cmd[i]); + if (i == comp_size - 1) + sb.append (NTXT ("=#\n")); + else + sb.append (NTXT (":")); + } + return sb.toString (); +} + +// Process a timeline-mode setting +Cmd_status +Settings::proc_tlmode (char *cmd, bool rc) +{ + bool got_tlmode, got_stack_align, got_stack_depth, got; + int ck_tlmode = 0, ck_stack_align = 0, ck_stack_depth = 0; + int len, i; + char *mcmd, *param; + int cmd_id, value = 0; + TLModeSubcommand cmd_type; + Cmd_status status; + char buf[BUFSIZ], *list; + if (cmd == NULL) + return CMD_BAD; + got_tlmode = got_stack_align = got_stack_depth = false; + snprintf (buf, sizeof (buf), NTXT ("%s"), cmd); + list = buf; + while ((mcmd = strtok (list, NTXT (":"))) != NULL) + { + list = NULL; + + // Find parameter after '=' + param = strchr (mcmd, '='); + if (param) + { + *param = '\0'; + param++; + } + status = CMD_OK; + got = false; + cmd_id = 0; + cmd_type = TLCMD_INVALID; + len = (int) strlen (mcmd); + for (i = 0; status == CMD_OK && i < tlmode_size; i++) + { + if (!strncasecmp (mcmd, tlmode_cmd[i].cmdText, len)) + { + if (got) // Ambiguous timeline mode + status = CMD_AMBIGUOUS; + else + { + got = true; + cmd_type = tlmode_cmd[i].cmdType; + cmd_id = tlmode_cmd[i].cmdId; + + // Check argument + if (cmd_type == TLCMD_DEPTH) + { + if (param == NULL) + status = CMD_BAD_ARG; + else + { + value = (int) strtol (param, ¶m, 10); + if (value <= 0 || value > 256) + status = CMD_OUTRANGE; + } + } + else if (param != NULL) + status = CMD_BAD_ARG; + } + } + } + + // Not valid timeline mode + if (!got) + status = CMD_INVALID; + if (status != CMD_OK) + { + if (!rc) + return status; + continue; + } + + // Set bits + switch (cmd_type) + { + case TLCMD_ENTITY_MODE: + got_tlmode = true; + ck_tlmode = cmd_id; + break; + case TLCMD_ALIGN: + got_stack_align = true; + ck_stack_align = cmd_id; + break; + case TLCMD_DEPTH: + got_stack_depth = true; + ck_stack_depth = value; + break; + default: + break; + } + } + + // No error, update + if (got_tlmode) + tlmode = ck_tlmode; + if (got_stack_align) + stack_align = ck_stack_align; + if (got_stack_depth) + stack_depth = ck_stack_depth; + return CMD_OK; +} + +// Process timeline data specification +Cmd_status +Settings::proc_tldata (const char *cmd, bool /* if true, ignore any error */) +{ + free (tldata); + tldata = dbe_strdup (cmd); // let GUI parse it + return CMD_OK; +} + +void +Settings::set_tldata (const char* _tldata_str) +{ + free (tldata); + tldata = dbe_strdup (_tldata_str); +} + +char* +Settings::get_tldata () +{ + return dbe_strdup (tldata); +} + +Cmd_status +Settings::set_name_format (char *arg) +{ + char *colon = strchr (arg, ':'); + size_t arg_len = (colon) ? (colon - arg) : strlen (arg); + Histable::NameFormat fname_fmt = Histable::NA; + if (!strncasecmp (arg, NTXT ("long"), arg_len)) + fname_fmt = Histable::LONG; + else if (!strncasecmp (arg, NTXT ("short"), arg_len)) + fname_fmt = Histable::SHORT; + else if (!strncasecmp (arg, NTXT ("mangled"), arg_len)) + fname_fmt = Histable::MANGLED; + else + return CMD_BAD_ARG; + + bool soname_fmt = false; + if (colon && (colon + 1)) + { + colon++; + if (!strcasecmp (colon, NTXT ("soname"))) + soname_fmt = true; + else if (!strcasecmp (colon, NTXT ("nosoname"))) + soname_fmt = false; + else + return CMD_BAD_ARG; + } + name_format = Histable::make_fmt (fname_fmt, soname_fmt); + return CMD_OK; +} + +void +Settings::buildMasterTabList () +{ + tab_list = new Vector<DispTab*>; + int i = -1; + + // Add tabs for all the known reports + tab_list->append (new DispTab (DSP_DEADLOCKS, i, false, DEADLOCK_EVNTS)); + tab_list->append (new DispTab (DSP_FUNCTION, i, false, FUNCS)); + tab_list->append (new DispTab (DSP_TIMELINE, i, false, TIMELINE)); + tab_list->append (new DispTab (DSP_CALLTREE, i, false, CALLTREE)); + tab_list->append (new DispTab (DSP_CALLFLAME, i, false, CALLFLAME)); + tab_list->append (new DispTab (DSP_DUALSOURCE, i, false, DUALSOURCE)); + tab_list->append (new DispTab (DSP_SOURCE_DISASM, i, false, SOURCEDISAM)); + tab_list->append (new DispTab (DSP_SOURCE, i, false, SOURCE)); + tab_list->append (new DispTab (DSP_LINE, i, false, HOTLINES)); + tab_list->append (new DispTab (DSP_DISASM, i, false, DISASM)); + tab_list->append (new DispTab (DSP_PC, i, false, HOTPCS)); + tab_list->append (new DispTab (DSP_LEAKLIST, i, false, LEAKS)); + tab_list->append (new DispTab (DSP_IOACTIVITY, i, false, IOACTIVITY)); + tab_list->append (new DispTab (DSP_HEAPCALLSTACK, i, false, HEAP)); + tab_list->append (new DispTab (DSP_IFREQ, i, false, IFREQ)); + tab_list->append (new DispTab (DSP_CALLER, i, false, GPROF)); + tab_list->append (new DispTab (DSP_STATIS, i, false, STATISTICS)); + tab_list->append (new DispTab (DSP_EXP, i, false, HEADER)); +} + +// Update tablist based on data availability +void +Settings::updateTabAvailability () +{ + int index; + DispTab *dsptab; + + Vec_loop (DispTab*, tab_list, index, dsptab) + { + if (dsptab->type == DSP_DATAOBJ) + dsptab->setAvailability (dbeSession->is_datamode_available ()); + else if (dsptab->type == DSP_DLAYOUT) + dsptab->setAvailability (dbeSession->is_datamode_available ()); + else if (dsptab->type == DSP_LEAKLIST) + dsptab->setAvailability (false); + else if (dsptab->type == DSP_IOACTIVITY) + dsptab->setAvailability (dbeSession->is_iodata_available ()); + else if (dsptab->type == DSP_HEAPCALLSTACK) + dsptab->setAvailability (dbeSession->is_heapdata_available ()); + else if (dsptab->type == DSP_TIMELINE) + dsptab->setAvailability (dbeSession->is_timeline_available ()); + else if (dsptab->type == DSP_IFREQ) + dsptab->setAvailability (dbeSession->is_ifreq_available ()); + else if (dsptab->type == DSP_RACES) + dsptab->setAvailability (dbeSession->is_racelist_available ()); + else if (dsptab->type == DSP_DEADLOCKS) + dsptab->setAvailability (dbeSession->is_deadlocklist_available ()); + else if (dsptab->type == DSP_DUALSOURCE) + dsptab->setAvailability (dbeSession->is_racelist_available () + || dbeSession->is_deadlocklist_available ()); + } +} + +// Process a tab setting +Cmd_status +Settings::proc_tabs (bool _rdtMode) +{ + int arg_cnt, cparam; + int count = 0; + int index; + DispTab *dsptab; + char *cmd; + if (tabs_processed == true) + return CMD_OK; + tabs_processed = true; + if (_rdtMode == true) + { + if (str_rtabs == NULL) + str_rtabs = strdup ("header"); + cmd = str_rtabs; + } + else + { + if (str_tabs == NULL) + str_tabs = strdup ("header"); + cmd = str_tabs; + } + if (strcmp (cmd, NTXT ("none")) == 0) + return CMD_OK; + Vector <char *> *tokens = split_str (cmd, ':'); + for (long j = 0, sz = VecSize (tokens); j < sz; j++) + { + char *tabname = tokens->get (j); + // search for this tab command token + CmdType c = Command::get_command (tabname, arg_cnt, cparam); + if (c == INDXOBJ) + { + // set the bit for this subtype + indx_tab_state->store (cparam, true); + indx_tab_order->store (cparam, count++); + } + else + { + // search for this tab type in the regular tabs + Vec_loop (DispTab*, tab_list, index, dsptab) + { + if (dsptab->cmdtoken == c) + { + dsptab->visible = true; + dsptab->order = count++; + break; + } + } + } + free (tabname); + } + delete tokens; + return CMD_OK; +} + +void +Settings::set_MemTabState (Vector<bool>*selected) +{ + if (selected->size () == 0) + return; + for (int j = 0; j < mem_tab_state->size (); j++) + mem_tab_state->store (j, selected->fetch (j)); +} + +// define a new memory object type + +void +Settings::mobj_define (MemObjType_t */* mobj */, bool state) +{ + if (mem_tab_state->size () == 0) + state = true; + mem_tab_state->append (state); + mem_tab_order->append (-1); +} + +void +Settings::set_IndxTabState (Vector<bool>*selected) +{ + for (int j = 0; j < selected->size (); j++) + indx_tab_state->store (j, selected->fetch (j)); +} + +// define a new index object type +void +Settings::indxobj_define (int type, bool state) +{ + indx_tab_state->store (type, state); + indx_tab_order->store (type, -1); +} + +void +Settings::set_pathmaps (Vector<pathmap_t*> *newPathMap) +{ + if (pathmaps) + { + pathmaps->destroy (); + delete pathmaps; + } + pathmaps = newPathMap; +} + +static char * +get_canonical_name (const char *fname) +{ + char *nm = dbe_strdup (fname); + for (size_t len = strlen (nm); (len > 0) && (nm[len - 1] == '/'); len--) + nm[len - 1] = 0; + return nm; +} + +char * +Settings::add_pathmap (Vector<pathmap_t*> *v, const char *from, const char *to) +{ + // Check for errors + if (from == NULL || to == NULL) + return dbe_strdup (GTXT ("Pathmap can have neither from nor to as NULL\n")); + if (strcmp (from, to) == 0) + return dbe_strdup (GTXT ("Pathmap from must differ from to\n")); + char *old_prefix = get_canonical_name (from); + char *new_prefix = get_canonical_name (to); + + // Check the pathmap list + for (int i = 0, sz = v->size (); i < sz; i++) + { + pathmap_t *pmp = v->get (i); + if ((strcmp (pmp->old_prefix, old_prefix) == 0) &&(strcmp (pmp->new_prefix, new_prefix) == 0)) + { + char *s = dbe_sprintf (GTXT ("Pathmap from `%s' to `%s' already exists\n"), old_prefix, new_prefix); + free (old_prefix); + free (new_prefix); + return s; + } + } + // construct a map for this pair + pathmap_t *thismap = new pathmap_t; + thismap->old_prefix = old_prefix; + thismap->new_prefix = new_prefix; + v->append (thismap); + return NULL; +} + +// Set all shared object expands back to .rc file defaults, +// as stored in the DbeSession Settings +bool +Settings::set_libdefaults () +{ + // See if this is unchanged + if (is_loexpand_default == true) + return false; // no change + + // replicate the DbeSession's lo_expand vector and default settings + lo_expand_t *this_lo_ex; + lo_expand_t *new_lo_ex; + int index; + lo_expand_default = dbeSession->get_settings ()->lo_expand_default; + lo_expands = new Vector<lo_expand_t*>; + Vec_loop (lo_expand_t*, dbeSession->get_settings ()->lo_expands, index, this_lo_ex) + { + new_lo_ex = new lo_expand_t; + new_lo_ex->libname = dbe_strdup (this_lo_ex->libname); + new_lo_ex->expand = this_lo_ex->expand; + lo_expands->append (new_lo_ex); + } + is_loexpand_default = true; + return true; +} + +bool +Settings::set_libexpand (char *cov, enum LibExpand expand, bool rc) +{ + int index; + lo_expand_t *loe; + bool change = false; + if (cov == NULL || !strcasecmp (cov, Command::ALL_CMD)) + { // set all libraries + // set the default + if (lo_expand_default != expand) + { + lo_expand_default = expand; + change = true; + is_loexpand_default = false; + } + + // and force any explicit settings to match, too + Vec_loop (lo_expand_t*, lo_expands, index, loe) + { + if (loe->expand != expand) + { + loe->expand = expand; + change = true; + is_loexpand_default = false; + } + } + + } + else + { // parsing coverage + Vector <char *> *tokens = split_str (cov, ','); + for (long j = 0, sz = VecSize (tokens); j < sz; j++) + { + char *lo_name = tokens->get (j); + char *newname = get_basename (lo_name); + bool found = false; + Vec_loop (lo_expand_t*, lo_expands, index, loe) + { + if (strcmp (loe->libname, newname) == 0) + { + if (loe->expand != expand) + { + if (rc == false) + { + loe->expand = expand; + change = true; + is_loexpand_default = false; + } + } + found = true; + break; + } + } + + if (found == false) + { + // construct a map for this pair + lo_expand_t *thisloe; + thisloe = new lo_expand_t; + thisloe->libname = dbe_strdup (newname); + thisloe->expand = expand; + change = true; + is_loexpand_default = false; + + // add it to the vector + lo_expands->append (thisloe); + } + free (lo_name); + } + delete tokens; + } + return change; +} + +enum LibExpand +Settings::get_lo_setting (char *name) +{ + int index; + lo_expand_t *loe; + char *lo_name = get_basename (name); + Vec_loop (lo_expand_t*, lo_expands, index, loe) + { + if (strcmp (loe->libname, lo_name) == 0) + return loe->expand; + } + return lo_expand_default; +} |