]>
Commit | Line | Data |
---|---|---|
c906108c | 1 | /* Miscellaneous simulator utilities. |
4a94e368 | 2 | Copyright (C) 1997-2022 Free Software Foundation, Inc. |
c906108c SS |
3 | Contributed by Cygnus Support. |
4 | ||
5 | This file is part of GDB, the GNU debugger. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
4744ac1b JB |
9 | the Free Software Foundation; either version 3 of the License, or |
10 | (at your option) any later version. | |
c906108c SS |
11 | |
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
4744ac1b JB |
17 | You should have received a copy of the GNU General Public License |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
c906108c | 19 | |
6df01ab8 MF |
20 | /* This must come before any other includes. */ |
21 | #include "defs.h" | |
22 | ||
2c29882f | 23 | #include <stdarg.h> |
c906108c | 24 | #include <stdlib.h> |
20a8e078 | 25 | #include <string.h> |
c906108c | 26 | #include <time.h> |
c906108c SS |
27 | #ifdef HAVE_SYS_RESOURCE_H |
28 | #include <sys/resource.h> | |
29 | #endif | |
20a8e078 | 30 | #include <sys/time.h> /* needed by sys/resource.h */ |
c906108c | 31 | |
c906108c | 32 | #include "bfd.h" |
20a8e078 MF |
33 | #include "libiberty.h" |
34 | ||
1352aabb OS |
35 | #include "sim-main.h" |
36 | #include "sim-assert.h" | |
c906108c SS |
37 | #include "sim-utils.h" |
38 | ||
982807ce | 39 | /* Allocate zero filled memory with xcalloc - xcalloc aborts if the |
c906108c SS |
40 | allocation fails. */ |
41 | ||
42 | void * | |
43 | zalloc (unsigned long size) | |
44 | { | |
982807ce | 45 | return xcalloc (1, size); |
c906108c SS |
46 | } |
47 | ||
c906108c SS |
48 | /* Allocate a sim_state struct. */ |
49 | ||
50 | SIM_DESC | |
383861bd MF |
51 | sim_state_alloc_extra (SIM_OPEN_KIND kind, host_callback *callback, |
52 | size_t extra_bytes) | |
c906108c SS |
53 | { |
54 | SIM_DESC sd = ZALLOC (struct sim_state); | |
55 | ||
56 | STATE_MAGIC (sd) = SIM_MAGIC_NUMBER; | |
57 | STATE_CALLBACK (sd) = callback; | |
58 | STATE_OPEN_KIND (sd) = kind; | |
59 | ||
383861bd MF |
60 | if (extra_bytes) |
61 | STATE_ARCH_DATA (sd) = zalloc (extra_bytes); | |
383861bd | 62 | |
c906108c SS |
63 | #if 0 |
64 | { | |
65 | int cpu_nr; | |
66 | ||
67 | /* Initialize the back link from the cpu struct to the state struct. */ | |
68 | /* ??? I can envision a design where the state struct contains an array | |
69 | of pointers to cpu structs, rather than an array of structs themselves. | |
70 | Implementing this is trickier as one may not know what to allocate until | |
71 | one has parsed the args. Parsing the args twice wouldn't be unreasonable, | |
72 | IMHO. If the state struct ever does contain an array of pointers then we | |
73 | can't do this here. | |
74 | ??? See also sim_post_argv_init*/ | |
75 | for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) | |
76 | { | |
77 | CPU_STATE (STATE_CPU (sd, cpu_nr)) = sd; | |
78 | CPU_INDEX (STATE_CPU (sd, cpu_nr)) = cpu_nr; | |
79 | } | |
80 | } | |
81 | #endif | |
82 | ||
83 | #ifdef SIM_STATE_INIT | |
84 | SIM_STATE_INIT (sd); | |
85 | #endif | |
86 | ||
87 | return sd; | |
88 | } | |
89 | ||
90 | /* Free a sim_state struct. */ | |
91 | ||
92 | void | |
93 | sim_state_free (SIM_DESC sd) | |
94 | { | |
44ddb0c6 | 95 | ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); |
c906108c SS |
96 | |
97 | #ifdef SIM_STATE_FREE | |
98 | SIM_STATE_FREE (sd); | |
99 | #endif | |
100 | ||
e8f20a28 | 101 | free (STATE_PROG_FILE (sd)); |
852016f9 | 102 | free (STATE_PROG_ARGV0 (sd)); |
54f7a83a | 103 | freeargv (STATE_PROG_ENVP (sd)); |
d79fe0d6 | 104 | free (sd); |
c906108c SS |
105 | } |
106 | ||
107 | /* Return a pointer to the cpu data for CPU_NAME, or NULL if not found. */ | |
108 | ||
109 | sim_cpu * | |
110 | sim_cpu_lookup (SIM_DESC sd, const char *cpu_name) | |
111 | { | |
112 | int i; | |
113 | ||
114 | for (i = 0; i < MAX_NR_PROCESSORS; ++i) | |
115 | if (strcmp (cpu_name, CPU_NAME (STATE_CPU (sd, i))) == 0) | |
116 | return STATE_CPU (sd, i); | |
117 | return NULL; | |
118 | } | |
119 | ||
120 | /* Return the prefix to use for a CPU specific message (typically an | |
121 | error message). */ | |
122 | ||
123 | const char * | |
124 | sim_cpu_msg_prefix (sim_cpu *cpu) | |
125 | { | |
126 | #if MAX_NR_PROCESSORS == 1 | |
127 | return ""; | |
128 | #else | |
129 | static char *prefix; | |
130 | ||
131 | if (prefix == NULL) | |
132 | { | |
133 | int maxlen = 0; | |
134 | for (i = 0; i < MAX_NR_PROCESSORS; ++i) | |
135 | { | |
136 | int len = strlen (CPU_NAME (STATE_CPU (sd, i))); | |
137 | if (len > maxlen) | |
138 | maxlen = len; | |
139 | } | |
140 | prefix = (char *) xmalloc (maxlen + 5); | |
141 | } | |
142 | sprintf (prefix, "%s: ", CPU_NAME (cpu)); | |
143 | return prefix; | |
144 | #endif | |
145 | } | |
146 | ||
147 | /* Cover fn to sim_io_eprintf. */ | |
148 | ||
149 | void | |
150 | sim_io_eprintf_cpu (sim_cpu *cpu, const char *fmt, ...) | |
151 | { | |
152 | SIM_DESC sd = CPU_STATE (cpu); | |
153 | va_list ap; | |
154 | ||
155 | va_start (ap, fmt); | |
d946c288 | 156 | sim_io_eprintf (sd, "%s", sim_cpu_msg_prefix (cpu)); |
c906108c SS |
157 | sim_io_evprintf (sd, fmt, ap); |
158 | va_end (ap); | |
159 | } | |
160 | ||
161 | /* Turn VALUE into a string with commas. */ | |
162 | ||
163 | char * | |
164 | sim_add_commas (char *buf, int sizeof_buf, unsigned long value) | |
165 | { | |
166 | int comma = 3; | |
167 | char *endbuf = buf + sizeof_buf - 1; | |
168 | ||
169 | *--endbuf = '\0'; | |
170 | do { | |
171 | if (comma-- == 0) | |
172 | { | |
173 | *--endbuf = ','; | |
174 | comma = 2; | |
175 | } | |
176 | ||
177 | *--endbuf = (value % 10) + '0'; | |
178 | } while ((value /= 10) != 0); | |
179 | ||
180 | return endbuf; | |
181 | } | |
182 | ||
183 | /* Analyze PROG_NAME/PROG_BFD and set these fields in the state struct: | |
184 | STATE_ARCHITECTURE, if not set already and can be determined from the bfd | |
185 | STATE_PROG_BFD | |
186 | STATE_START_ADDR | |
187 | STATE_TEXT_SECTION | |
188 | STATE_TEXT_START | |
189 | STATE_TEXT_END | |
190 | ||
191 | PROG_NAME is the file name of the executable or NULL. | |
192 | PROG_BFD is its bfd or NULL. | |
193 | ||
194 | If both PROG_NAME and PROG_BFD are NULL, this function returns immediately. | |
195 | If PROG_BFD is not NULL, PROG_NAME is ignored. | |
196 | ||
197 | Implicit inputs: STATE_MY_NAME(sd), STATE_TARGET(sd), | |
198 | STATE_ARCHITECTURE(sd). | |
199 | ||
200 | A new bfd is created so the app isn't required to keep its copy of the | |
201 | bfd open. */ | |
202 | ||
203 | SIM_RC | |
b2b255bd | 204 | sim_analyze_program (SIM_DESC sd, const char *prog_name, bfd *prog_bfd) |
c906108c SS |
205 | { |
206 | asection *s; | |
207 | SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); | |
208 | ||
209 | if (prog_bfd != NULL) | |
210 | { | |
211 | if (prog_bfd == STATE_PROG_BFD (sd)) | |
212 | /* already analyzed */ | |
213 | return SIM_RC_OK; | |
214 | else | |
215 | /* duplicate needed, save the name of the file to be re-opened */ | |
216 | prog_name = bfd_get_filename (prog_bfd); | |
217 | } | |
218 | ||
219 | /* do we need to duplicate anything? */ | |
220 | if (prog_name == NULL) | |
221 | return SIM_RC_OK; | |
222 | ||
223 | /* open a new copy of the prog_bfd */ | |
224 | prog_bfd = bfd_openr (prog_name, STATE_TARGET (sd)); | |
225 | if (prog_bfd == NULL) | |
226 | { | |
028f6515 | 227 | sim_io_eprintf (sd, "%s: can't open \"%s\": %s\n", |
c906108c SS |
228 | STATE_MY_NAME (sd), |
229 | prog_name, | |
230 | bfd_errmsg (bfd_get_error ())); | |
231 | return SIM_RC_FAIL; | |
232 | } | |
028f6515 | 233 | if (!bfd_check_format (prog_bfd, bfd_object)) |
c906108c SS |
234 | { |
235 | sim_io_eprintf (sd, "%s: \"%s\" is not an object file: %s\n", | |
236 | STATE_MY_NAME (sd), | |
237 | prog_name, | |
238 | bfd_errmsg (bfd_get_error ())); | |
239 | bfd_close (prog_bfd); | |
240 | return SIM_RC_FAIL; | |
241 | } | |
242 | if (STATE_ARCHITECTURE (sd) != NULL) | |
243 | bfd_set_arch_info (prog_bfd, STATE_ARCHITECTURE (sd)); | |
244 | else | |
245 | { | |
246 | if (bfd_get_arch (prog_bfd) != bfd_arch_unknown | |
247 | && bfd_get_arch (prog_bfd) != bfd_arch_obscure) | |
248 | { | |
249 | STATE_ARCHITECTURE (sd) = bfd_get_arch_info (prog_bfd); | |
250 | } | |
251 | } | |
252 | ||
253 | /* update the sim structure */ | |
254 | if (STATE_PROG_BFD (sd) != NULL) | |
255 | bfd_close (STATE_PROG_BFD (sd)); | |
256 | STATE_PROG_BFD (sd) = prog_bfd; | |
257 | STATE_START_ADDR (sd) = bfd_get_start_address (prog_bfd); | |
258 | ||
259 | for (s = prog_bfd->sections; s; s = s->next) | |
fd361982 | 260 | if (strcmp (bfd_section_name (s), ".text") == 0) |
c906108c SS |
261 | { |
262 | STATE_TEXT_SECTION (sd) = s; | |
fd361982 AM |
263 | STATE_TEXT_START (sd) = bfd_section_vma (s); |
264 | STATE_TEXT_END (sd) = STATE_TEXT_START (sd) + bfd_section_size (s); | |
c906108c SS |
265 | break; |
266 | } | |
267 | ||
2836ee25 FCE |
268 | bfd_cache_close (prog_bfd); |
269 | ||
c906108c SS |
270 | return SIM_RC_OK; |
271 | } | |
272 | \f | |
273 | /* Simulator timing support. */ | |
274 | ||
275 | /* Called before sim_elapsed_time_since to get a reference point. */ | |
276 | ||
277 | SIM_ELAPSED_TIME | |
dc416615 | 278 | sim_elapsed_time_get (void) |
c906108c SS |
279 | { |
280 | #ifdef HAVE_GETRUSAGE | |
281 | struct rusage mytime; | |
282 | if (getrusage (RUSAGE_SELF, &mytime) == 0) | |
283 | return 1 + (SIM_ELAPSED_TIME) (((double) mytime.ru_utime.tv_sec * 1000) + (((double) mytime.ru_utime.tv_usec + 500) / 1000)); | |
284 | return 1; | |
285 | #else | |
286 | #ifdef HAVE_TIME | |
287 | return 1 + (SIM_ELAPSED_TIME) time ((time_t) 0); | |
288 | #else | |
289 | return 1; | |
290 | #endif | |
291 | #endif | |
292 | } | |
293 | ||
294 | /* Return the elapsed time in milliseconds since START. | |
6439295f | 295 | The actual time may be cpu usage (preferred) or wall clock. */ |
c906108c SS |
296 | |
297 | unsigned long | |
dc416615 | 298 | sim_elapsed_time_since (SIM_ELAPSED_TIME start) |
c906108c SS |
299 | { |
300 | #ifdef HAVE_GETRUSAGE | |
301 | return sim_elapsed_time_get () - start; | |
302 | #else | |
303 | #ifdef HAVE_TIME | |
304 | return (sim_elapsed_time_get () - start) * 1000; | |
305 | #else | |
306 | return 0; | |
307 | #endif | |
308 | #endif | |
309 | } | |
310 | ||
311 | ||
312 | ||
313 | /* do_command but with printf style formatting of the arguments */ | |
314 | void | |
315 | sim_do_commandf (SIM_DESC sd, | |
316 | const char *fmt, | |
317 | ...) | |
318 | { | |
319 | va_list ap; | |
320 | char *buf; | |
2561d580 MF |
321 | int ret; |
322 | ||
c906108c | 323 | va_start (ap, fmt); |
2561d580 MF |
324 | ret = vasprintf (&buf, fmt, ap); |
325 | va_end (ap); | |
326 | ||
327 | if (ret < 0) | |
39a3ae0a MF |
328 | { |
329 | sim_io_eprintf (sd, "%s: asprintf failed for `%s'\n", | |
330 | STATE_MY_NAME (sd), fmt); | |
331 | return; | |
332 | } | |
2561d580 | 333 | |
c906108c | 334 | sim_do_command (sd, buf); |
c906108c SS |
335 | free (buf); |
336 | } | |
337 | ||
338 | ||
339 | /* sim-basics.h defines a number of enumerations, convert each of them | |
340 | to a string representation */ | |
341 | const char * | |
342 | map_to_str (unsigned map) | |
343 | { | |
344 | switch (map) | |
345 | { | |
346 | case read_map: return "read"; | |
347 | case write_map: return "write"; | |
348 | case exec_map: return "exec"; | |
349 | case io_map: return "io"; | |
350 | default: | |
351 | { | |
f47674be PK |
352 | static char str[16]; |
353 | snprintf (str, sizeof(str), "(%ld)", (long) map); | |
c906108c SS |
354 | return str; |
355 | } | |
356 | } | |
357 | } | |
358 | ||
359 | const char * | |
360 | access_to_str (unsigned access) | |
361 | { | |
362 | switch (access) | |
363 | { | |
364 | case access_invalid: return "invalid"; | |
365 | case access_read: return "read"; | |
366 | case access_write: return "write"; | |
367 | case access_exec: return "exec"; | |
368 | case access_io: return "io"; | |
369 | case access_read_write: return "read_write"; | |
370 | case access_read_exec: return "read_exec"; | |
371 | case access_write_exec: return "write_exec"; | |
372 | case access_read_write_exec: return "read_write_exec"; | |
373 | case access_read_io: return "read_io"; | |
374 | case access_write_io: return "write_io"; | |
375 | case access_read_write_io: return "read_write_io"; | |
376 | case access_exec_io: return "exec_io"; | |
377 | case access_read_exec_io: return "read_exec_io"; | |
378 | case access_write_exec_io: return "write_exec_io"; | |
379 | case access_read_write_exec_io: return "read_write_exec_io"; | |
380 | default: | |
381 | { | |
f47674be PK |
382 | static char str[16]; |
383 | snprintf (str, sizeof(str), "(%ld)", (long) access); | |
c906108c SS |
384 | return str; |
385 | } | |
386 | } | |
387 | } | |
388 | ||
389 | const char * | |
390 | transfer_to_str (unsigned transfer) | |
391 | { | |
392 | switch (transfer) | |
393 | { | |
394 | case read_transfer: return "read"; | |
395 | case write_transfer: return "write"; | |
396 | default: return "(error)"; | |
397 | } | |
398 | } |