]>
Commit | Line | Data |
---|---|---|
76bdc726 | 1 | /* Copyright (C) 2021-2023 Free Software Foundation, Inc. |
bb368aad VM |
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 <unistd.h> | |
23 | #include <fcntl.h> | |
24 | ||
25 | #include "util.h" | |
26 | #include "DbeApplication.h" | |
27 | #include "DbeSession.h" | |
28 | #include "Function.h" | |
29 | #include "LoadObject.h" | |
30 | #include "Module.h" | |
31 | #include "DbeView.h" | |
32 | #include "Print.h" | |
33 | #include "DbeFile.h" | |
34 | #include "Command.h" | |
35 | ||
36 | class er_src : public DbeApplication | |
37 | { | |
38 | public: | |
39 | er_src (int argc, char *argv[]); | |
40 | void start (int argc, char *argv[]); | |
41 | ||
42 | private: | |
43 | ||
44 | // override methods in base class | |
45 | void usage (); | |
46 | int check_args (int argc, char *argv[]); | |
47 | void run_args (int argc, char *argv[]); | |
48 | ||
49 | enum Obj_Types | |
50 | { | |
51 | OT_EXE_ELF = 0, OT_JAVA_CLASS, OT_JAR_FILE, OT_UNKNOWN | |
52 | }; | |
53 | ||
54 | void open (char *exe); | |
55 | void dump_annotated (char *name, char* sel, char *src, DbeView *dbev, | |
56 | bool is_dis, bool first); | |
57 | void checkJavaClass (char *exe); | |
58 | void print_header (bool first, const char* text); | |
59 | void proc_cmd (CmdType cmd_type, bool first, char *arg1, | |
60 | const char *arg2, const char *arg3 = NULL); | |
61 | FILE *set_outfile (char *cmd, FILE *&set_file); | |
62 | ||
63 | bool is_java_class () { return obj_type == OT_JAVA_CLASS; } | |
64 | ||
65 | int dbevindex; | |
66 | DbeView *dbev; | |
67 | LoadObject *lo; | |
68 | Obj_Types obj_type; | |
69 | const char *out_fname; | |
70 | FILE *out_file; | |
71 | bool isDisasm; | |
72 | bool isFuncs; | |
73 | bool isDFuncs; | |
74 | bool isSrc; | |
75 | bool v_opt; | |
76 | int multiple; | |
77 | char *str_compcom; | |
78 | bool hex_visible; | |
79 | int src_visible; | |
80 | int vis_src; | |
81 | int vis_dis; | |
82 | int threshold_src; | |
83 | int threshold_dis; | |
84 | int threshold; | |
85 | int vis_bits; | |
86 | }; | |
87 | ||
88 | static int | |
89 | real_main (int argc, char *argv[]) | |
90 | { | |
91 | er_src *src = new er_src (argc, argv); | |
92 | src->start (argc, argv); | |
93 | delete src; | |
94 | return 0; | |
95 | } | |
96 | ||
97 | int | |
98 | main (int argc, char *argv[]) | |
99 | { | |
100 | return catch_out_of_memory (real_main, argc, argv); | |
101 | } | |
102 | ||
103 | er_src::er_src (int argc, char *argv[]) | |
104 | : DbeApplication (argc, argv) | |
105 | { | |
106 | obj_type = OT_UNKNOWN; | |
107 | out_fname = "<stdout>"; | |
108 | out_file = stdout; | |
109 | isDisasm = false; | |
110 | isFuncs = false; | |
111 | isDFuncs = false; | |
112 | isSrc = false; | |
113 | v_opt = false; | |
114 | multiple = 0; | |
115 | lo = NULL; | |
116 | } | |
117 | ||
118 | static int | |
119 | FuncNameCmp (const void *a, const void *b) | |
120 | { | |
121 | Function *item1 = *((Function **) a); | |
122 | Function *item2 = *((Function **) b); | |
123 | return strcmp (item1->get_mangled_name (), item2->get_mangled_name ()); | |
124 | } | |
125 | ||
126 | static int | |
127 | FuncAddrCmp (const void *a, const void *b) | |
128 | { | |
129 | Function *item1 = *((Function **) a); | |
130 | Function *item2 = *((Function **) b); | |
131 | return (item1->img_offset == item2->img_offset) ? | |
132 | FuncNameCmp (a, b) : item1->img_offset > item2->img_offset ? 1 : -1; | |
133 | } | |
134 | ||
135 | void | |
136 | er_src::usage () | |
137 | { | |
138 | ||
139 | /* | |
140 | Ruud - Isolate this line because it has an argument. Otherwise it would be at the | |
141 | end of a long usage list. | |
142 | */ | |
143 | printf ( GTXT ( | |
144 | "Usage: gprofng display src [OPTION(S)] TARGET-OBJECT\n")); | |
145 | ||
146 | printf ( GTXT ( | |
147 | "\n" | |
148 | "Display the source code listing, or source code interleaved with disassembly code,\n" | |
149 | "as extracted from the target object (an executable, shared object, object file, or\n" | |
150 | "a Java .class file).\n" | |
151 | "\n" | |
152 | "Options:\n" | |
153 | "\n" | |
154 | " --version print the version number and exit.\n" | |
155 | " --help print usage information and exit.\n" | |
156 | " --verbose {on|off} enable (on) or disable (off) verbose mode; the default is \"off\".\n" | |
157 | "\n" | |
158 | " -func list all the functions from the given object.\n" | |
159 | "\n" | |
160 | " -source item tag show the source code for item; the tag is used to\n" | |
161 | " differentiate in case of multiple occurences with\n" | |
162 | " the same name; the combination of \"all -1\" selects\n" | |
163 | " all the functions in the object; the default is\n" | |
164 | " \"-source all -1\".\n" | |
165 | "\n" | |
166 | " -disasm item tag show the source code, interleaved with the disassembled\n" | |
167 | " instructions; the same definitions for item and tag apply.\n" | |
168 | "\n" | |
169 | " -outfile <filename> write results to file <filename>; a dash (-) writes to\n" | |
170 | " stdout; this is also the default; note that this only\n" | |
171 | " affects options included to the right of this option.\n" | |
172 | "\n" | |
173 | "Documentation:\n" | |
174 | "\n" | |
175 | "A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n" | |
176 | "gprofng programs are properly installed at your site, the command \"info gprofng\"\n" | |
177 | "should give you access to this document.\n" | |
178 | "\n" | |
179 | "See also:\n" | |
180 | "\n" | |
181 | "gprofng(1), gp-archive(1), gp-collect-app(1), gp-display-html(1), gp-display-text(1)\n")); | |
182 | /* | |
183 | printf (GTXT ("Usage: %s [OPTION] a.out/.so/.o/.class\n\n"), whoami); | |
184 | printf (GTXT (" -func List all the functions from the given object\n" | |
185 | " -source, -src item tag Show the annotated source for the listed item\n" | |
186 | " -disasm item tag Include the disassembly in the listing\n" | |
187 | " -V Print the current release version of er_src\n" | |
188 | " -cc, -scc, -dcc com_spec Define the compiler commentary classes to show\n" | |
189 | " -outfile filename Open filename for output\n")); | |
190 | */ | |
191 | exit (0); | |
192 | } | |
193 | ||
194 | void | |
195 | er_src::start (int argc, char *argv[]) | |
196 | { | |
197 | dbevindex = dbeSession->createView (0, -1); | |
198 | dbev = dbeSession->getView (dbevindex); | |
199 | ||
200 | // get options | |
201 | check_args (argc, argv); | |
202 | run_args (argc, argv); | |
203 | if (out_file != stdout) | |
204 | fclose (out_file); | |
205 | } | |
206 | ||
207 | FILE * | |
208 | er_src::set_outfile (char *cmd, FILE *&set_file) | |
209 | { | |
210 | FILE *new_file; | |
211 | if (!strcasecmp (cmd, "-")) | |
212 | { | |
213 | new_file = stdout; | |
214 | out_fname = "<stdout>"; | |
215 | } | |
216 | else | |
217 | { | |
218 | char *cmdpath; | |
219 | char *fname = strstr (cmd, "~/"); | |
220 | // Handle ~ in file names | |
221 | char *home = getenv ("HOME"); | |
222 | if (fname != NULL && home != NULL) | |
223 | cmdpath = dbe_sprintf ("%s/%s", home, fname + 2); | |
224 | else if ((fname = strstr (cmd, "~")) != NULL && home != NULL) | |
225 | cmdpath = dbe_sprintf ("/home/%s", fname + 1); | |
226 | else | |
227 | cmdpath = strdup (cmd); | |
228 | new_file = fopen (cmdpath, "w"); | |
229 | if (new_file == NULL) | |
230 | { | |
231 | fprintf (stderr, GTXT ("Unable to open file: %s"), cmdpath); | |
232 | free (cmdpath); | |
233 | return NULL; | |
234 | } | |
235 | out_fname = cmdpath; | |
236 | } | |
237 | if (set_file && (set_file != stdout)) | |
238 | fclose (set_file); | |
239 | ||
240 | set_file = new_file; | |
241 | return set_file; | |
242 | } | |
243 | ||
244 | void | |
245 | er_src::proc_cmd (CmdType cmd_type, bool first, char *arg1, | |
246 | const char *arg2, const char *arg3) | |
247 | { | |
248 | Cmd_status status; | |
249 | Module *module; | |
250 | Function *fitem; | |
251 | int mindex, findex; | |
252 | switch (cmd_type) | |
253 | { | |
254 | case SOURCE: | |
255 | dbev->set_view_mode (VMODE_USER); | |
256 | print_anno_file (arg1, arg2, arg3, false, | |
257 | stdout, stdin, out_file, dbev, false); | |
258 | break; | |
259 | case DISASM: | |
260 | dbev->set_view_mode (VMODE_MACHINE); | |
261 | print_header (first, GTXT ("Annotated disassembly\n")); | |
262 | print_anno_file (arg1, arg2, arg3, true, | |
263 | stdout, stdin, out_file, dbev, false); | |
264 | break; | |
265 | case OUTFILE: | |
266 | if (arg1) | |
267 | set_outfile (arg1, out_file); | |
268 | break; | |
269 | case FUNCS: | |
270 | print_header (false, GTXT ("Function list\n")); | |
271 | fprintf (out_file, GTXT ("Functions sorted in lexicographic order\n")); | |
272 | fprintf (out_file, GTXT ("\nLoad Object: %s\n\n"), lo->get_name ()); | |
273 | if (lo->wsize == W32) | |
274 | fprintf (out_file, GTXT (" Address Size Name\n\n")); | |
275 | else | |
276 | fprintf (out_file, GTXT (" Address Size Name\n\n")); | |
277 | ||
278 | Vec_loop (Module*, lo->seg_modules, mindex, module) | |
279 | { | |
280 | module->functions->sort (FuncNameCmp); | |
281 | const char *fmt = (lo->wsize == W32) ? | |
282 | GTXT (" 0x%08llx %8lld %s\n") : | |
283 | GTXT (" 0x%016llx %16lld %s\n"); | |
284 | Vec_loop (Function*, module->functions, findex, fitem) | |
285 | { | |
286 | fprintf (out_file, fmt, | |
287 | (ull_t) fitem->img_offset, | |
288 | (ull_t) fitem->size, | |
289 | fitem->get_name ()); | |
290 | } | |
291 | } | |
292 | break; | |
293 | case DUMPFUNC: | |
294 | lo->functions->sort (FuncAddrCmp); | |
295 | print_header (first, GTXT ("Dump functions\n")); | |
296 | lo->dump_functions (out_file); | |
297 | first = false; | |
298 | break; | |
299 | case SCOMPCOM: | |
300 | status = dbev->proc_compcom (arg1, true, false); | |
301 | if (status != CMD_OK) | |
302 | fprintf (stderr, GTXT ("Error: %s"), Command::get_err_string (status)); | |
303 | break; | |
304 | case DCOMPCOM: | |
305 | status = dbev->proc_compcom (arg1, false, false); | |
306 | if (status != CMD_OK) | |
307 | fprintf (stderr, GTXT ("Error: %s"), Command::get_err_string (status)); | |
308 | break; | |
309 | case COMPCOM: | |
310 | status = dbev->proc_compcom (arg1, true, false); | |
311 | if (status != CMD_OK) | |
312 | fprintf (stderr, GTXT ("Error: %s: %s"), Command::get_err_string (status), arg1); | |
313 | status = dbev->proc_compcom (arg1, false, false); | |
314 | if (status != CMD_OK) | |
315 | fprintf (stderr, GTXT ("Error: %s: %s"), Command::get_err_string (status), arg1); | |
316 | break; | |
317 | case HELP: | |
318 | usage (); | |
319 | break; | |
320 | case VERSION_cmd: | |
321 | if (out_file != stdout) | |
322 | // Ruud | |
323 | Application::print_version_info (); | |
324 | /* | |
325 | fprintf (out_file, "GNU %s version %s\n", get_basename (prog_name), VERSION); | |
326 | */ | |
327 | break; | |
328 | default: | |
329 | fprintf (stderr, GTXT ("Invalid option")); | |
330 | break; | |
331 | } | |
332 | } | |
333 | ||
334 | void | |
335 | er_src::run_args (int argc, char *argv[]) | |
336 | { | |
337 | CmdType cmd_type; | |
338 | int arg_count, cparam; | |
339 | char *arg; | |
340 | char *arg1; | |
341 | const char *arg2; | |
342 | bool first = true; | |
343 | bool space; | |
344 | Module *module; | |
345 | int mindex; | |
346 | ||
347 | for (int i = 1; i < argc; i++) | |
348 | { | |
349 | if (*argv[i] != '-') | |
350 | { | |
351 | if (!multiple) | |
352 | { // er_src -V exe | |
353 | space = false; | |
354 | dbev->set_view_mode (VMODE_USER); | |
355 | print_header (first, GTXT ("Annotated source\n")); | |
356 | Vec_loop (Module*, lo->seg_modules, mindex, module) | |
357 | { | |
358 | if ((module->flags & MOD_FLAG_UNKNOWN) != 0 || | |
359 | module->lang_code == Sp_lang_unknown) | |
360 | continue; | |
361 | if (space) | |
362 | fprintf (out_file, "\n"); | |
363 | print_anno_file (module->file_name, "1", NULL, false, | |
364 | stdout, stdin, out_file, dbev, false); | |
365 | space = true; | |
366 | } | |
367 | } | |
368 | break; | |
369 | } | |
370 | if (strncmp (argv[i], NTXT ("--whoami="), 9) == 0) | |
371 | { | |
372 | whoami = argv[i] + 9; | |
373 | continue; | |
374 | } | |
375 | switch (cmd_type = Command::get_command (argv[i] + 1, arg_count, cparam)) | |
376 | { | |
377 | case SOURCE: | |
378 | case DISASM: | |
379 | { | |
380 | i += arg_count; | |
381 | multiple++; | |
382 | if (i >= argc || argv[i] == NULL || | |
383 | (*(argv[i]) == '-' && atoi (argv[i]) != -1) || i + 1 == argc) | |
384 | { | |
385 | i--; | |
386 | arg = argv[i]; | |
387 | arg2 = "1"; | |
388 | } | |
389 | else | |
390 | { | |
391 | arg = argv[i - 1]; | |
392 | if (*(argv[i]) == '-' && atoi (argv[i]) == -1 && | |
393 | streq (arg, NTXT ("all"))) | |
394 | { | |
395 | space = false; | |
396 | if (cmd_type == SOURCE) | |
397 | print_header (first, GTXT ("Annotated source\n")); | |
398 | else | |
399 | print_header (first, GTXT ("Annotated disassembly\n")); | |
400 | Vec_loop (Module*, lo->seg_modules, mindex, module) | |
401 | { | |
402 | if ((module->flags & MOD_FLAG_UNKNOWN) != 0 || | |
403 | module->lang_code == Sp_lang_unknown) | |
404 | continue; | |
405 | if (space) | |
406 | fprintf (out_file, "\n"); | |
407 | proc_cmd (cmd_type, first, module->file_name, "1"); | |
408 | space = true; | |
409 | } | |
410 | first = false; | |
411 | break; | |
412 | } | |
413 | arg2 = argv[i]; | |
414 | } | |
415 | char *fcontext = NULL; | |
416 | arg1 = parse_fname (arg, &fcontext); | |
417 | if (arg1 == NULL) | |
418 | { | |
419 | fprintf (stderr, GTXT ("Error: Invalid function/file setting: %s\n"), arg1); | |
420 | free (fcontext); | |
421 | break; | |
422 | } | |
423 | proc_cmd (cmd_type, first, arg1, arg2, fcontext); | |
424 | free (arg1); | |
425 | free (fcontext); | |
426 | first = false; | |
427 | break; | |
428 | } | |
429 | case OUTFILE: | |
430 | case FUNCS: | |
431 | case DUMPFUNC: | |
432 | case COMPCOM: | |
433 | case SCOMPCOM: | |
434 | case DCOMPCOM: | |
435 | case VERSION_cmd: | |
436 | case HELP: | |
437 | proc_cmd (cmd_type, first, (arg_count > 0) ? argv[i + 1] : NULL, | |
438 | (arg_count > 1) ? argv[i + 2] : NULL); | |
439 | i += arg_count; | |
440 | break; | |
441 | default: | |
442 | if (streq (argv[i] + 1, NTXT ("all")) || streq (argv[i] + 1, NTXT ("dall"))) | |
443 | { | |
444 | first = false; | |
445 | multiple++; | |
446 | if (streq (argv[i] + 1, NTXT ("all"))) | |
447 | proc_cmd (FUNCS, first, NULL, NULL); | |
448 | else | |
449 | proc_cmd (DUMPFUNC, first, NULL, NULL); | |
450 | space = false; | |
451 | print_header (first, GTXT ("Annotated source\n")); | |
452 | Vec_loop (Module*, lo->seg_modules, mindex, module) | |
453 | { | |
454 | if ((module->flags & MOD_FLAG_UNKNOWN) != 0 || | |
455 | module->lang_code == Sp_lang_unknown) | |
456 | continue; | |
457 | if (space) | |
458 | fprintf (out_file, "\n"); | |
459 | proc_cmd (SOURCE, first, module->file_name, "1"); | |
460 | space = true; | |
461 | } | |
462 | print_header (first, GTXT ("Annotated disassembly\n")); | |
463 | Vec_loop (Module*, lo->seg_modules, mindex, module) | |
464 | { | |
465 | if ((module->flags & MOD_FLAG_UNKNOWN) != 0 || | |
466 | module->lang_code == Sp_lang_unknown) | |
467 | continue; | |
468 | if (space) | |
469 | fprintf (out_file, "\n"); | |
470 | proc_cmd (DISASM, first, module->file_name, "1"); | |
471 | space = true; | |
472 | } | |
473 | } | |
474 | else | |
475 | { | |
476 | proc_cmd (cmd_type, first, (arg_count > 0) ? argv[i + 1] : NULL, | |
477 | (arg_count > 1) ? argv[i + 2] : NULL); | |
478 | i += arg_count; | |
479 | break; | |
480 | } | |
481 | } | |
482 | } | |
483 | } | |
484 | ||
485 | int | |
486 | er_src::check_args (int argc, char *argv[]) | |
487 | { | |
488 | CmdType cmd_type = UNKNOWN_CMD; | |
489 | int arg_count, cparam; | |
490 | int i; | |
491 | char *exe; | |
492 | bool first = true; | |
493 | if (argc == 1) | |
494 | usage (); | |
495 | ||
496 | // If any comments from the .rc files, log them to stderr | |
497 | Emsg * rcmsg = fetch_comments (); | |
498 | while (rcmsg != NULL) | |
499 | { | |
500 | fprintf (stderr, "%s: %s\n", prog_name, rcmsg->get_msg ()); | |
501 | rcmsg = rcmsg->next; | |
502 | } | |
503 | ||
504 | // Parsing the command line | |
505 | opterr = 0; | |
506 | exe = NULL; | |
507 | for (i = 1; i < argc; i++) | |
508 | { | |
509 | if (*argv[i] != '-') | |
510 | { | |
511 | exe = argv[i]; | |
512 | if (i == 1) | |
513 | { // er_src exe ? | |
514 | if (!exe) | |
515 | usage (); | |
516 | if (argc == 3) // er_src exe file | |
517 | usage (); | |
518 | } | |
519 | else if (v_opt && !multiple && !exe && !str_compcom) // just er_src -V | |
520 | exit (0); | |
521 | if (argc < i + 1 || argc > i + 3) | |
522 | usage (); | |
523 | i++; | |
524 | if (argc > i) | |
525 | usage (); | |
526 | open (exe); | |
527 | return i; | |
528 | } | |
529 | switch (cmd_type = Command::get_command (argv[i] + 1, arg_count, cparam)) | |
530 | { | |
531 | case WHOAMI: | |
532 | whoami = argv[i] + 1 + cparam; | |
533 | break; | |
534 | case HELP: | |
535 | i += arg_count; | |
536 | multiple++; | |
537 | usage (); | |
538 | break; | |
539 | case VERSION_cmd: | |
540 | if (first) | |
541 | { | |
542 | // Ruud | |
543 | Application::print_version_info (); | |
544 | /* | |
545 | printf ("GNU %s version %s\n", get_basename (prog_name), VERSION); | |
546 | */ | |
547 | v_opt = true; | |
548 | first = false; | |
549 | } | |
550 | break; | |
551 | case SOURCE: | |
552 | case DISASM: | |
553 | i += arg_count; | |
554 | multiple++; | |
555 | isDisasm = true; | |
556 | if (i >= argc || argv[i] == NULL || | |
557 | (*(argv[i]) == '-' && atoi (argv[i]) != -1) || (i + 1 == argc)) | |
558 | i--; | |
559 | break; | |
560 | case DUMPFUNC: | |
561 | i += arg_count; | |
562 | multiple++; | |
563 | break; | |
564 | case FUNCS: | |
565 | i += arg_count; | |
566 | multiple++; | |
567 | break; | |
568 | case OUTFILE: | |
569 | case COMPCOM: | |
570 | case SCOMPCOM: | |
571 | case DCOMPCOM: | |
572 | i += arg_count; | |
573 | break; | |
574 | default: | |
575 | if (!(streq (argv[i] + 1, NTXT ("all")) || | |
576 | streq (argv[i] + 1, NTXT ("dall")))) | |
577 | { | |
578 | fprintf (stderr, "Error: invalid option: `%s'\n", argv[i]); | |
579 | exit (1); | |
580 | } | |
581 | } | |
582 | } | |
583 | if (!exe && !(argc == 2 && cmd_type == VERSION_cmd)) | |
584 | usage (); | |
585 | return i; | |
586 | } | |
587 | ||
588 | void | |
589 | er_src::checkJavaClass (char* exe) | |
590 | { | |
591 | unsigned char cf_buf[4]; | |
592 | unsigned int magic_number; | |
593 | int fd = ::open (exe, O_RDONLY | O_LARGEFILE); | |
594 | if (fd == -1) | |
595 | return; | |
596 | if (sizeof (cf_buf) == read_from_file (fd, cf_buf, sizeof (cf_buf))) | |
597 | { | |
598 | magic_number = cf_buf[0] << 24; | |
599 | magic_number |= cf_buf[1] << 16; | |
600 | magic_number |= cf_buf[2] << 8; | |
601 | magic_number |= cf_buf[3]; | |
602 | if (magic_number == 0xcafebabe) | |
603 | obj_type = OT_JAVA_CLASS; | |
604 | } | |
605 | close (fd); | |
606 | } | |
607 | ||
608 | void | |
609 | er_src::print_header (bool first, const char* text) | |
610 | { | |
611 | if (!first) | |
612 | fprintf (out_file, "\n"); | |
613 | if (multiple > 1) | |
614 | { | |
615 | fprintf (out_file, NTXT ("%s"), text); | |
616 | fprintf (out_file, "---------------------------------------\n"); | |
617 | } | |
618 | } | |
619 | ||
620 | void | |
621 | er_src::dump_annotated (char *name, char *sel, char *src, DbeView *dbevr, | |
622 | bool is_dis, bool first) | |
623 | { | |
624 | Module *module; | |
625 | bool space; | |
626 | int mindex; | |
627 | print_header (first, (is_dis) ? ((is_java_class ()) ? | |
628 | GTXT ("Annotated bytecode\n") : | |
629 | GTXT ("Annotated disassembly\n")) : | |
630 | GTXT ("Annotated source\n")); | |
631 | if (!name) | |
632 | { | |
633 | space = false; | |
634 | Vec_loop (Module*, lo->seg_modules, mindex, module) | |
635 | { | |
636 | if ((module->flags & MOD_FLAG_UNKNOWN) != 0 || | |
637 | (!is_dis && module->lang_code == Sp_lang_unknown)) | |
638 | continue; | |
639 | if (space) | |
640 | fprintf (out_file, "\n"); | |
641 | print_anno_file (module->file_name, sel, src, is_dis, | |
642 | stdout, stdin, out_file, dbevr, false); | |
643 | space = true; | |
644 | } | |
645 | } | |
646 | else | |
647 | print_anno_file (name, sel, src, is_dis, stdout, stdin, out_file, dbevr, false); | |
648 | } | |
649 | ||
650 | static bool | |
651 | isFatal (bool isDisasm, LoadObject::Arch_status status) | |
652 | { | |
653 | if (isDisasm) | |
654 | { | |
655 | switch (status) | |
656 | { | |
657 | // non-fatal errors for disassembly | |
658 | case LoadObject::ARCHIVE_BAD_STABS: | |
659 | case LoadObject::ARCHIVE_NO_STABS: | |
660 | return false; | |
661 | default: | |
662 | return true; | |
663 | } | |
664 | } | |
665 | return true; | |
666 | } | |
667 | ||
668 | void | |
669 | er_src::open (char *exe) | |
670 | { | |
671 | LoadObject::Arch_status status; | |
672 | char *errstr; | |
673 | Module *module; | |
674 | Vector<Histable*> *module_lst; | |
675 | ||
676 | // Construct the Segment structure | |
677 | char *path = strdup (exe); | |
678 | lo = dbeSession->createLoadObject (path); | |
679 | if (NULL == lo->dbeFile->find_file (lo->dbeFile->get_name ())) | |
680 | { | |
681 | fprintf (stderr, GTXT ("%s: Error: unable to open file %s\n"), prog_name, lo->dbeFile->get_name ()); | |
682 | exit (1); | |
683 | } | |
684 | checkJavaClass (exe); | |
685 | ||
686 | if (is_java_class ()) | |
687 | { | |
688 | lo->type = LoadObject::SEG_TEXT; | |
689 | lo->set_platform (Java, Wnone); | |
690 | lo->id = (uint64_t) - 1; // see AnalyzerSession::ask_which for details | |
691 | module = dbeSession->createClassFile (dbe_strdup (exe)); | |
692 | module->loadobject = lo; | |
693 | lo->seg_modules->append (module); | |
694 | module->dbeFile->set_location (exe); | |
695 | if (module->readFile () != module->AE_OK) | |
696 | { | |
697 | Emsg *emsg = module->get_error (); | |
698 | if (emsg) | |
699 | { | |
700 | fprintf (stderr, GTXT ("%s: Error: %s\n"), prog_name, emsg->get_msg ()); | |
701 | return; | |
702 | } | |
703 | fprintf (stderr, GTXT ("%s: Error: Could not read class file `%s'\n"), prog_name, exe); | |
704 | return; | |
705 | } | |
706 | status = lo->sync_read_stabs (); | |
707 | if (status != LoadObject::ARCHIVE_SUCCESS) | |
708 | { | |
709 | if (status == LoadObject::ARCHIVE_ERR_OPEN) | |
710 | { | |
711 | fprintf (stderr, GTXT ("%s: Error: Could not read class file `%s'\n"), prog_name, exe); | |
712 | return; | |
713 | } | |
714 | else | |
715 | { | |
716 | if (isDisasm) | |
717 | if (status == LoadObject::ARCHIVE_NO_STABS) | |
718 | { | |
719 | fprintf (stderr, GTXT ("%s: Error: `%s' is interface; disassembly annotation not available\n"), prog_name, exe); | |
720 | return; | |
721 | } | |
722 | } | |
723 | } | |
724 | } | |
725 | else | |
726 | { | |
727 | status = lo->sync_read_stabs (); | |
728 | if (status != LoadObject::ARCHIVE_SUCCESS) | |
729 | { | |
730 | errstr = lo->status_str (status); | |
731 | if (errstr) | |
732 | { | |
733 | fprintf (stderr, "%s: %s\n", prog_name, errstr); | |
734 | free (errstr); | |
735 | } | |
736 | if (isFatal (isDisasm, status)) | |
737 | return; | |
738 | } | |
739 | obj_type = OT_EXE_ELF; | |
740 | ||
741 | // if .o file, then set file as the exe name | |
742 | if (lo->is_relocatable ()) | |
743 | { | |
744 | // find the module, if we can | |
745 | module_lst = new Vector<Histable*>; | |
746 | module = dbeSession->map_NametoModule (path, module_lst, 0); | |
747 | if (module == NULL) | |
748 | // Create a module with the right name | |
749 | module = dbeSession->createModule (lo, path); | |
750 | } | |
751 | } | |
752 | } |