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