Commit | Line | Data |
---|---|---|
e2207b9a JK |
1 | /* GDB routines for supporting auto-loaded scripts. |
2 | ||
3 | Copyright (C) 2012 Free Software Foundation, Inc. | |
4 | ||
5 | This file is part of GDB. | |
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 | |
9 | the Free Software Foundation; either version 3 of the License, or | |
10 | (at your option) any later version. | |
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 | ||
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/>. */ | |
19 | ||
20 | #include "defs.h" | |
21 | #include "auto-load.h" | |
22 | #include "progspace.h" | |
23 | #include "python/python.h" | |
24 | #include "gdb_regex.h" | |
25 | #include "ui-out.h" | |
26 | #include "filenames.h" | |
27 | #include "command.h" | |
28 | #include "observer.h" | |
29 | #include "objfiles.h" | |
30 | #include "python/python-internal.h" | |
31 | ||
32 | /* Internal-use flag to enable/disable auto-loading. | |
33 | This is true if we should auto-load python code when an objfile is opened, | |
34 | false otherwise. | |
35 | ||
36 | Both auto_load_scripts && gdbpy_global_auto_load must be true to enable | |
37 | auto-loading. | |
38 | ||
39 | This flag exists to facilitate deferring auto-loading during start-up | |
40 | until after ./.gdbinit has been read; it may augment the search directories | |
41 | used to find the scripts. */ | |
42 | int gdbpy_global_auto_load = 1; | |
43 | ||
44 | /* For scripts specified in .debug_gdb_scripts, multiple objfiles may load | |
45 | the same script. There's no point in loading the script multiple times, | |
46 | and there can be a lot of objfiles and scripts, so we keep track of scripts | |
47 | loaded this way. */ | |
48 | ||
49 | struct auto_load_pspace_info | |
50 | { | |
51 | /* For each program space we keep track of loaded scripts. */ | |
52 | struct htab *loaded_scripts; | |
53 | ||
54 | /* Non-zero if we've issued the warning about an auto-load script not being | |
55 | found. We only want to issue this warning once. */ | |
56 | int script_not_found_warning_printed; | |
57 | }; | |
58 | ||
59 | /* Objects of this type are stored in the loaded script hash table. */ | |
60 | ||
61 | struct loaded_script | |
62 | { | |
63 | /* Name as provided by the objfile. */ | |
64 | const char *name; | |
65 | /* Full path name or NULL if script wasn't found (or was otherwise | |
66 | inaccessible). */ | |
67 | const char *full_path; | |
68 | }; | |
69 | ||
70 | /* Per-program-space data key. */ | |
71 | static const struct program_space_data *auto_load_pspace_data; | |
72 | ||
73 | static void | |
74 | auto_load_pspace_data_cleanup (struct program_space *pspace, void *arg) | |
75 | { | |
76 | struct auto_load_pspace_info *info; | |
77 | ||
78 | info = program_space_data (pspace, auto_load_pspace_data); | |
79 | if (info != NULL) | |
80 | { | |
81 | if (info->loaded_scripts) | |
82 | htab_delete (info->loaded_scripts); | |
83 | xfree (info); | |
84 | } | |
85 | } | |
86 | ||
87 | /* Get the current autoload data. If none is found yet, add it now. This | |
88 | function always returns a valid object. */ | |
89 | ||
90 | static struct auto_load_pspace_info * | |
91 | get_auto_load_pspace_data (struct program_space *pspace) | |
92 | { | |
93 | struct auto_load_pspace_info *info; | |
94 | ||
95 | info = program_space_data (pspace, auto_load_pspace_data); | |
96 | if (info == NULL) | |
97 | { | |
98 | info = XZALLOC (struct auto_load_pspace_info); | |
99 | set_program_space_data (pspace, auto_load_pspace_data, info); | |
100 | } | |
101 | ||
102 | return info; | |
103 | } | |
104 | ||
105 | /* Hash function for the loaded script hash. */ | |
106 | ||
107 | static hashval_t | |
108 | hash_loaded_script_entry (const void *data) | |
109 | { | |
110 | const struct loaded_script *e = data; | |
111 | ||
112 | return htab_hash_string (e->name); | |
113 | } | |
114 | ||
115 | /* Equality function for the loaded script hash. */ | |
116 | ||
117 | static int | |
118 | eq_loaded_script_entry (const void *a, const void *b) | |
119 | { | |
120 | const struct loaded_script *ea = a; | |
121 | const struct loaded_script *eb = b; | |
122 | ||
123 | return strcmp (ea->name, eb->name) == 0; | |
124 | } | |
125 | ||
126 | /* Initialize the table to track loaded scripts. | |
127 | Each entry is hashed by the full path name. */ | |
128 | ||
129 | static void | |
130 | init_loaded_scripts_info (struct auto_load_pspace_info *pspace_info) | |
131 | { | |
132 | /* Choose 31 as the starting size of the hash table, somewhat arbitrarily. | |
133 | Space for each entry is obtained with one malloc so we can free them | |
134 | easily. */ | |
135 | ||
136 | pspace_info->loaded_scripts = htab_create (31, | |
137 | hash_loaded_script_entry, | |
138 | eq_loaded_script_entry, | |
139 | xfree); | |
140 | ||
141 | pspace_info->script_not_found_warning_printed = FALSE; | |
142 | } | |
143 | ||
144 | /* Wrapper on get_auto_load_pspace_data to also allocate the hash table | |
145 | for loading scripts. */ | |
146 | ||
147 | struct auto_load_pspace_info * | |
148 | get_auto_load_pspace_data_for_loading (struct program_space *pspace) | |
149 | { | |
150 | struct auto_load_pspace_info *info; | |
151 | ||
152 | info = get_auto_load_pspace_data (pspace); | |
153 | if (info->loaded_scripts == NULL) | |
154 | init_loaded_scripts_info (info); | |
155 | ||
156 | return info; | |
157 | } | |
158 | ||
159 | /* Add script NAME to hash table of PSPACE_INFO. | |
160 | FULL_PATH is NULL if the script wasn't found. | |
161 | The result is true if the script was already in the hash table. */ | |
162 | ||
163 | int | |
164 | maybe_add_script (struct auto_load_pspace_info *pspace_info, const char *name, | |
165 | const char *full_path) | |
166 | { | |
167 | struct htab *htab = pspace_info->loaded_scripts; | |
168 | struct loaded_script **slot, entry; | |
169 | int in_hash_table; | |
170 | ||
171 | entry.name = name; | |
172 | entry.full_path = full_path; | |
173 | slot = (struct loaded_script **) htab_find_slot (htab, &entry, INSERT); | |
174 | in_hash_table = *slot != NULL; | |
175 | ||
176 | /* If this script is not in the hash table, add it. */ | |
177 | ||
178 | if (! in_hash_table) | |
179 | { | |
180 | char *p; | |
181 | ||
182 | /* Allocate all space in one chunk so it's easier to free. */ | |
183 | *slot = xmalloc (sizeof (**slot) | |
184 | + strlen (name) + 1 | |
185 | + (full_path != NULL ? (strlen (full_path) + 1) : 0)); | |
186 | p = ((char*) *slot) + sizeof (**slot); | |
187 | strcpy (p, name); | |
188 | (*slot)->name = p; | |
189 | if (full_path != NULL) | |
190 | { | |
191 | p += strlen (p) + 1; | |
192 | strcpy (p, full_path); | |
193 | (*slot)->full_path = p; | |
194 | } | |
195 | else | |
196 | (*slot)->full_path = NULL; | |
197 | } | |
198 | ||
199 | return in_hash_table; | |
200 | } | |
201 | ||
202 | /* Clear the table of loaded section scripts. */ | |
203 | ||
204 | static void | |
205 | clear_section_scripts (void) | |
206 | { | |
207 | struct program_space *pspace = current_program_space; | |
208 | struct auto_load_pspace_info *info; | |
209 | ||
210 | info = program_space_data (pspace, auto_load_pspace_data); | |
211 | if (info != NULL && info->loaded_scripts != NULL) | |
212 | { | |
213 | htab_delete (info->loaded_scripts); | |
214 | info->loaded_scripts = NULL; | |
215 | info->script_not_found_warning_printed = FALSE; | |
216 | } | |
217 | } | |
218 | ||
219 | /* Look for the auto-load script associated with OBJFILE and load it. */ | |
220 | ||
221 | void | |
222 | auto_load_objfile_script (struct objfile *objfile, const char *suffix) | |
223 | { | |
224 | char *realname; | |
225 | char *filename, *debugfile; | |
226 | int len; | |
227 | FILE *input; | |
228 | struct cleanup *cleanups; | |
229 | ||
230 | realname = gdb_realpath (objfile->name); | |
231 | len = strlen (realname); | |
232 | filename = xmalloc (len + strlen (suffix) + 1); | |
233 | memcpy (filename, realname, len); | |
234 | strcpy (filename + len, suffix); | |
235 | ||
236 | cleanups = make_cleanup (xfree, filename); | |
237 | make_cleanup (xfree, realname); | |
238 | ||
239 | input = fopen (filename, "r"); | |
240 | debugfile = filename; | |
241 | ||
242 | if (!input && debug_file_directory) | |
243 | { | |
244 | /* Also try the same file in the separate debug info directory. */ | |
245 | debugfile = xmalloc (strlen (filename) | |
246 | + strlen (debug_file_directory) + 1); | |
247 | strcpy (debugfile, debug_file_directory); | |
248 | /* FILENAME is absolute, so we don't need a "/" here. */ | |
249 | strcat (debugfile, filename); | |
250 | ||
251 | make_cleanup (xfree, debugfile); | |
252 | input = fopen (debugfile, "r"); | |
253 | } | |
254 | ||
255 | if (!input && gdb_datadir) | |
256 | { | |
257 | /* Also try the same file in a subdirectory of gdb's data | |
258 | directory. */ | |
259 | debugfile = xmalloc (strlen (gdb_datadir) + strlen (filename) | |
260 | + strlen ("/auto-load") + 1); | |
261 | strcpy (debugfile, gdb_datadir); | |
262 | strcat (debugfile, "/auto-load"); | |
263 | /* FILENAME is absolute, so we don't need a "/" here. */ | |
264 | strcat (debugfile, filename); | |
265 | ||
266 | make_cleanup (xfree, debugfile); | |
267 | input = fopen (debugfile, "r"); | |
268 | } | |
269 | ||
270 | if (input) | |
271 | { | |
272 | struct auto_load_pspace_info *pspace_info; | |
273 | ||
274 | make_cleanup_fclose (input); | |
275 | ||
276 | /* Add this script to the hash table too so "info auto-load-scripts" | |
277 | can print it. */ | |
278 | pspace_info = | |
279 | get_auto_load_pspace_data_for_loading (current_program_space); | |
280 | maybe_add_script (pspace_info, debugfile, debugfile); | |
281 | ||
282 | /* To preserve existing behaviour we don't check for whether the | |
283 | script was already in the table, and always load it. | |
284 | It's highly unlikely that we'd ever load it twice, | |
285 | and these scripts are required to be idempotent under multiple | |
286 | loads anyway. */ | |
287 | source_python_script_for_objfile (objfile, input, debugfile); | |
288 | } | |
289 | ||
290 | do_cleanups (cleanups); | |
291 | } | |
292 | ||
293 | /* This is a new_objfile observer callback to auto-load scripts. | |
294 | ||
295 | Two flavors of auto-loaded scripts are supported. | |
296 | 1) based on the path to the objfile | |
297 | 2) from .debug_gdb_scripts section */ | |
298 | ||
299 | static void | |
300 | auto_load_new_objfile (struct objfile *objfile) | |
301 | { | |
302 | if (!objfile) | |
303 | { | |
304 | /* OBJFILE is NULL when loading a new "main" symbol-file. */ | |
305 | clear_section_scripts (); | |
306 | return; | |
307 | } | |
308 | ||
309 | load_auto_scripts_for_objfile (objfile); | |
310 | } | |
311 | ||
312 | /* Collect scripts to be printed in a vec. */ | |
313 | ||
314 | typedef struct loaded_script *loaded_script_ptr; | |
315 | DEF_VEC_P (loaded_script_ptr); | |
316 | ||
317 | /* Traversal function for htab_traverse. | |
318 | Collect the entry if it matches the regexp. */ | |
319 | ||
320 | static int | |
321 | collect_matching_scripts (void **slot, void *info) | |
322 | { | |
323 | struct loaded_script *script = *slot; | |
324 | VEC (loaded_script_ptr) **scripts_ptr = info; | |
325 | ||
326 | if (re_exec (script->name)) | |
327 | VEC_safe_push (loaded_script_ptr, *scripts_ptr, script); | |
328 | ||
329 | return 1; | |
330 | } | |
331 | ||
332 | /* Print SCRIPT. */ | |
333 | ||
334 | static void | |
335 | print_script (struct loaded_script *script) | |
336 | { | |
337 | struct ui_out *uiout = current_uiout; | |
338 | struct cleanup *chain; | |
339 | ||
340 | chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); | |
341 | ||
342 | ui_out_field_string (uiout, "loaded", script->full_path ? "Yes" : "Missing"); | |
343 | ui_out_field_string (uiout, "script", script->name); | |
344 | ui_out_text (uiout, "\n"); | |
345 | ||
346 | /* If the name isn't the full path, print it too. */ | |
347 | if (script->full_path != NULL | |
348 | && strcmp (script->name, script->full_path) != 0) | |
349 | { | |
350 | ui_out_text (uiout, "\tfull name: "); | |
351 | ui_out_field_string (uiout, "full_path", script->full_path); | |
352 | ui_out_text (uiout, "\n"); | |
353 | } | |
354 | ||
355 | do_cleanups (chain); | |
356 | } | |
357 | ||
358 | /* Helper for info_auto_load_scripts to sort the scripts by name. */ | |
359 | ||
360 | static int | |
361 | sort_scripts_by_name (const void *ap, const void *bp) | |
362 | { | |
363 | const struct loaded_script *a = *(const struct loaded_script **) ap; | |
364 | const struct loaded_script *b = *(const struct loaded_script **) bp; | |
365 | ||
366 | return FILENAME_CMP (a->name, b->name); | |
367 | } | |
368 | ||
369 | /* "info auto-load-scripts" command. */ | |
370 | ||
371 | static void | |
372 | info_auto_load_scripts (char *pattern, int from_tty) | |
373 | { | |
374 | struct ui_out *uiout = current_uiout; | |
375 | struct auto_load_pspace_info *pspace_info; | |
376 | struct cleanup *script_chain; | |
377 | VEC (loaded_script_ptr) *scripts; | |
378 | int nr_scripts; | |
379 | ||
380 | dont_repeat (); | |
381 | ||
382 | pspace_info = get_auto_load_pspace_data (current_program_space); | |
383 | ||
384 | if (pattern && *pattern) | |
385 | { | |
386 | char *re_err = re_comp (pattern); | |
387 | ||
388 | if (re_err) | |
389 | error (_("Invalid regexp: %s"), re_err); | |
390 | } | |
391 | else | |
392 | { | |
393 | re_comp (""); | |
394 | } | |
395 | ||
396 | /* We need to know the number of rows before we build the table. | |
397 | Plus we want to sort the scripts by name. | |
398 | So first traverse the hash table collecting the matching scripts. */ | |
399 | ||
400 | scripts = VEC_alloc (loaded_script_ptr, 10); | |
401 | script_chain = make_cleanup (VEC_cleanup (loaded_script_ptr), &scripts); | |
402 | ||
403 | if (pspace_info != NULL && pspace_info->loaded_scripts != NULL) | |
404 | { | |
405 | immediate_quit++; | |
406 | /* Pass a pointer to scripts as VEC_safe_push can realloc space. */ | |
407 | htab_traverse_noresize (pspace_info->loaded_scripts, | |
408 | collect_matching_scripts, &scripts); | |
409 | immediate_quit--; | |
410 | } | |
411 | ||
412 | nr_scripts = VEC_length (loaded_script_ptr, scripts); | |
413 | make_cleanup_ui_out_table_begin_end (uiout, 2, nr_scripts, | |
414 | "AutoLoadedScriptsTable"); | |
415 | ||
416 | ui_out_table_header (uiout, 7, ui_left, "loaded", "Loaded"); | |
417 | ui_out_table_header (uiout, 70, ui_left, "script", "Script"); | |
418 | ui_out_table_body (uiout); | |
419 | ||
420 | if (nr_scripts > 0) | |
421 | { | |
422 | int i; | |
423 | loaded_script_ptr script; | |
424 | ||
425 | qsort (VEC_address (loaded_script_ptr, scripts), | |
426 | VEC_length (loaded_script_ptr, scripts), | |
427 | sizeof (loaded_script_ptr), sort_scripts_by_name); | |
428 | for (i = 0; VEC_iterate (loaded_script_ptr, scripts, i, script); ++i) | |
429 | print_script (script); | |
430 | } | |
431 | ||
432 | do_cleanups (script_chain); | |
433 | ||
434 | if (nr_scripts == 0) | |
435 | { | |
436 | if (pattern && *pattern) | |
437 | ui_out_message (uiout, 0, "No auto-load scripts matching %s.\n", | |
438 | pattern); | |
439 | else | |
440 | ui_out_message (uiout, 0, "No auto-load scripts.\n"); | |
441 | } | |
442 | } | |
443 | ||
444 | /* Return non-zero if SCRIPT_NOT_FOUND_WARNING_PRINTED of PSPACE_INFO was unset | |
445 | before calling this function. Always set SCRIPT_NOT_FOUND_WARNING_PRINTED | |
446 | of PSPACE_INFO. */ | |
447 | ||
448 | int | |
449 | script_not_found_warning_print (struct auto_load_pspace_info *pspace_info) | |
450 | { | |
451 | int retval = !pspace_info->script_not_found_warning_printed; | |
452 | ||
453 | pspace_info->script_not_found_warning_printed = 1; | |
454 | ||
455 | return retval; | |
456 | } | |
457 | ||
458 | void _initialize_auto_load (void); | |
459 | ||
460 | void | |
461 | _initialize_auto_load (void) | |
462 | { | |
463 | auto_load_pspace_data | |
464 | = register_program_space_data_with_cleanup (auto_load_pspace_data_cleanup); | |
465 | ||
466 | observer_attach_new_objfile (auto_load_new_objfile); | |
467 | ||
468 | add_info ("auto-load-scripts", | |
469 | info_auto_load_scripts, | |
470 | _("Print the list of automatically loaded scripts.\n\ | |
471 | Usage: info auto-load-scripts [REGEXP]")); | |
472 | } |