xref: /netbsd-src/external/gpl3/binutils.old/dist/gprofng/src/MachineModel.cc (revision 3117ece4fc4a4ca4489ba793710b60b0d26bab6c)
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 #include "config.h"
22 #include <string.h>
23 #include <unistd.h>
24 #include <dirent.h>
25 
26 #include "DbeSession.h"
27 #include "Command.h"
28 #include "Application.h"
29 #include "MemorySpace.h"
30 #include "i18n.h"
31 
32 #define MAXARGS     20
33 
34 static const char *LIBNAME = "../lib/analyzer/lib/machinemodels";
35 
36 char *
37 DbeSession::find_mach_model (char *name)
38 {
39   // Read current working directory to see if it's there
40   if (name[0] == '/')
41     {
42       // Absolute path given
43       char *path = dbe_sprintf (NTXT ("%s.ermm"), name);
44       if (access (path, R_OK | F_OK) == 0)
45 	return path;
46       free (path);
47       // Don't try anywhere else
48       return NULL;
49     }
50 
51   char *path = dbe_sprintf (NTXT ("./%s.ermm"), name);
52   if (access (path, R_OK | F_OK) == 0)
53     return path;
54   free (path);
55 
56 
57   // Read the user's home directory to see if it's there
58   char *home = getenv (NTXT ("HOME"));
59   if (home != NULL)
60     {
61       path = dbe_sprintf (NTXT ("%s/%s.ermm"), home, name);
62       if (access (path, R_OK | F_OK) == 0)
63 	return path;
64       free (path);
65     }
66   if (strchr (name, (int) '/') != NULL)
67     // name has a slash; don't look in system installation directory
68     return NULL;
69 
70   // Read system installation directory to see if it's there
71   path = dbe_sprintf ("%s/%s/%s.ermm", theApplication->get_run_dir (),
72 		      LIBNAME, name);
73   if (access (path, R_OK | F_OK) == 0)
74     return path;
75   free (path);
76   return NULL;
77 }
78 
79 //  Handle the definitions from a machinemodel file
80 //  Return value is NULL if it was OK, or an error message if not
81 char *
82 DbeSession::load_mach_model (char *_name)
83 {
84   CmdType cmd_type;
85   int arg_count, cparam;
86   char *cmd, *end_cmd;
87   char *arglist[MAXARGS];
88   char *ret = NULL;
89   char *path = NULL;
90   FILE *fptr = NULL;
91 
92   // Does name have .ermm suffix?  If so, strip it away
93   char *name = dbe_strdup (_name);
94   size_t len = strlen (name);
95   if (len > 5 && strcmp (name + len - 5, ".ermm") == 0)
96     name[len - 5] = 0;
97 
98   if ((mach_model_loaded != NULL) && (strcmp (name, mach_model_loaded) == 0))
99     {
100       ret = dbe_sprintf (GTXT ("Machine model %s is already loaded\n"), name);
101       free (name);
102       return ret;
103     }
104   else if (mach_model_loaded == NULL && len == 0)
105     {
106       ret = dbe_sprintf (GTXT ("No Machine model is loaded\n"));
107       free (name);
108       return ret;
109     }
110 
111   if (len != 0)
112     {
113       // zero-length just means unload any previously loaded model; only look if non-zero
114       path = find_mach_model (name);
115       if (path == NULL)
116 	{
117 	  ret = dbe_sprintf (GTXT ("Machine model %s not found\n"), name);
118 	  free (name);
119 	  return ret;
120 	}
121       fptr = fopen (path, NTXT ("r"));
122       if (fptr == NULL)
123 	{
124 	  ret = dbe_sprintf (GTXT ("Open of Machine model %s, file %s failed\n"), name, path);
125 	  free (path);
126 	  free (name);
127 	  return ret;
128 	}
129     }
130 
131   // We are now committed to make the new machine model the loaded one;
132   //   Delete any MemoryObjects from any previously loaded machinemodel
133   if (dbeSession->mach_model_loaded != NULL)
134     {
135       Vector <char *> *oldobjs = MemorySpace::getMachineModelMemObjs
136 	      (dbeSession->mach_model_loaded);
137       for (int i = 0; i < oldobjs->size (); i++)
138 	MemorySpace::mobj_delete (oldobjs->fetch (i));
139       delete oldobjs;
140       free (mach_model_loaded);
141     }
142   if (len == 0)
143     {
144       mach_model_loaded = NULL;
145       free (name);
146       // and there's no "loading" to do; just return
147       return NULL;
148     }
149   else
150     mach_model_loaded = name;
151 
152   int line_no = 0;
153   end_cmd = NULL;
154 
155   while (!feof (fptr))
156     {
157       char *script = read_line (fptr);
158       if (script == NULL)
159 	continue;
160 
161       line_no++;
162       strtok (script, NTXT ("\n"));
163 
164       // extract the command
165       cmd = strtok (script, NTXT (" \t"));
166       if (cmd == NULL || *cmd == '#' || *cmd == '\n')
167 	{
168 	  free (script);
169 	  continue;
170 	}
171 
172       char *remainder = strtok (NULL, NTXT ("\n"));
173       // now extract the arguments
174       int nargs = 0;
175       for (;;)
176 	{
177 	  if (nargs >= MAXARGS)
178 	    {
179 	      ret = dbe_sprintf (GTXT ("Warning: more than %d arguments to %s command, line %d\n"),
180 				 MAXARGS, cmd, line_no);
181 	      continue;
182 	    }
183 
184 	  char *nextarg = strtok (remainder, NTXT ("\n"));
185 
186 	  if (nextarg == NULL || *nextarg == '#')
187 	      // either the end of the line, or a comment indicator
188 	      break;
189 	  arglist[nargs++] = parse_qstring (nextarg, &end_cmd);
190 	  remainder = end_cmd;
191 	  if (remainder == NULL)
192 	    break;
193 
194 	  // skip any blanks or tabs to get to next argument
195 	  while ((*remainder == ' ') || (*remainder == '\t'))
196 	    remainder++;
197 	}
198 
199       cmd_type = Command::get_command (cmd, arg_count, cparam);
200       // check for extra arguments
201       if (cmd_type != UNKNOWN_CMD && cmd_type != INDXOBJDEF && nargs > arg_count)
202 	ret = dbe_sprintf (GTXT ("Warning: extra arguments to %s command, line %d\n"),
203 			   cmd, line_no);
204       if (nargs < arg_count)
205 	{
206 	  ret = dbe_sprintf (GTXT ("Error: missing arguments to %s command, line %d\n"),
207 			     cmd, line_no);
208 
209 	  // ignore this command
210 	  free (script);
211 	  continue;
212 	}
213 
214       switch (cmd_type)
215 	{
216 	case INDXOBJDEF:
217 	  {
218 	    char *err = dbeSession->indxobj_define (arglist[0], NULL,
219 			    arglist[1], (nargs >= 3) ? PTXT (arglist[2]) : NULL,
220 			    (nargs >= 4) ? PTXT (arglist[3]) : NULL);
221 	    if (err != NULL)
222 	      ret = dbe_sprintf (GTXT ("   %s: line %d `%s %s %s'\n"),
223 				 err, line_no, cmd, arglist[0], arglist[1]);
224 	    break;
225 	  }
226 	case COMMENT:
227 	  // ignore the line
228 	  break;
229 	default:
230 	  {
231 	    // unexpected command in a machinemodel file
232 	    ret = dbe_sprintf (GTXT ("Unexpected command in machinemodel file %s on line %d: `%.64s'\n"),
233 			       path, line_no, cmd);
234 	    break;
235 	  }
236 	}
237       free (script);
238     }
239   fclose (fptr);
240   return ret;
241 }
242 
243 Vector<char*> *
244 DbeSession::list_mach_models ()
245 {
246   Vector<char*> *model_names = new Vector<char*>();
247 
248   // Open the current directory to read the entries there
249   DIR *dir = opendir (NTXT ("."));
250   if (dir != NULL)
251     {
252       struct dirent *entry = NULL;
253       while ((entry = readdir (dir)) != NULL)
254 	{
255 	  size_t len = strlen (entry->d_name);
256 	  if (len < 5 || strcmp (entry->d_name + len - 5, ".ermm") != 0)
257 	    continue;
258 	  char *model = dbe_strdup (entry->d_name);
259 
260 	  // remove the .ermm suffix
261 	  model[len - 5] = 0;
262 
263 	  // add to vector
264 	  model_names->append (dbe_strdup (model));
265 	}
266       closedir (dir);
267     }
268 
269   // Read the user's home directory to list the models there
270   char *home = getenv ("HOME");
271   if (home != NULL)
272     {
273       dir = opendir (home);
274       if (dir != NULL)
275 	{
276 	  struct dirent *entry = NULL;
277 	  while ((entry = readdir (dir)) != NULL)
278 	    {
279 	      size_t len = strlen (entry->d_name);
280 	      if (len < 5 || strcmp (entry->d_name + len - 5, ".ermm") != 0)
281 		continue;
282 	      char *model = dbe_strdup (entry->d_name);
283 
284 	      // remove the .ermm suffix
285 	      model[len - 5] = 0;
286 
287 	      // add to vector
288 	      model_names->append (dbe_strdup (model));
289 	    }
290 	  closedir (dir);
291 	}
292     }
293 
294   // Read system installation directory to list the models there
295   char *sysdir = dbe_sprintf ("%s/%s", theApplication->get_run_dir (), LIBNAME);
296 
297   dir = opendir (sysdir);
298   if (dir != NULL)
299     {
300       struct dirent *entry = NULL;
301       while ((entry = readdir (dir)) != NULL)
302 	{
303 	  size_t len = strlen (entry->d_name);
304 	  if (len < 5 || strcmp (entry->d_name + len - 5, ".ermm") != 0)
305 	    continue;
306 	  char *model = dbe_strdup (entry->d_name);
307 
308 	  // remove the .ermm suffix
309 	  model[len - 5] = 0;
310 
311 	  // add to vector
312 	  model_names->append (dbe_strdup (model));
313 	}
314       closedir (dir);
315     }
316   return model_names;
317 }
318