1 /* Copyright (C) 2021-2023 Free Software Foundation, Inc.
4 This file is part of GNU Binutils.
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)
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.
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. */
26 #include "DbeApplication.h"
27 #include "DbeSession.h"
29 #include "LoadObject.h"
36 class er_src
: public DbeApplication
39 er_src (int argc
, char *argv
[]);
40 void start (int argc
, char *argv
[]);
44 // override methods in base class
46 int check_args (int argc
, char *argv
[]);
47 void run_args (int argc
, char *argv
[]);
51 OT_EXE_ELF
= 0, OT_JAVA_CLASS
, OT_JAR_FILE
, OT_UNKNOWN
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
);
63 bool is_java_class () { return obj_type
== OT_JAVA_CLASS
; }
69 const char *out_fname
;
89 real_main (int argc
, char *argv
[])
91 er_src
*src
= new er_src (argc
, argv
);
92 src
->start (argc
, argv
);
98 main (int argc
, char *argv
[])
100 return catch_out_of_memory (real_main
, argc
, argv
);
103 er_src::er_src (int argc
, char *argv
[])
104 : DbeApplication (argc
, argv
)
106 obj_type
= OT_UNKNOWN
;
107 out_fname
= "<stdout>";
119 FuncNameCmp (const void *a
, const void *b
)
121 Function
*item1
= *((Function
**) a
);
122 Function
*item2
= *((Function
**) b
);
123 return strcmp (item1
->get_mangled_name (), item2
->get_mangled_name ());
127 FuncAddrCmp (const void *a
, const void *b
)
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;
140 Ruud - Isolate this line because it has an argument. Otherwise it would be at the
141 end of a long usage list.
144 "Usage: gprofng display src [OPTION(S)] TARGET-OBJECT\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"
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"
158 " -func list all the functions from the given object.\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"
166 " -disasm item tag show the source code, interleaved with the disassembled\n"
167 " instructions; the same definitions for item and tag apply.\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"
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"
181 "gprofng(1), gp-archive(1), gp-collect-app(1), gp-display-html(1), gp-display-text(1)\n"));
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"));
195 er_src::start (int argc
, char *argv
[])
197 dbevindex
= dbeSession
->createView (0, -1);
198 dbev
= dbeSession
->getView (dbevindex
);
201 check_args (argc
, argv
);
202 run_args (argc
, argv
);
203 if (out_file
!= stdout
)
208 er_src::set_outfile (char *cmd
, FILE *&set_file
)
211 if (!strcasecmp (cmd
, "-"))
214 out_fname
= "<stdout>";
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);
227 cmdpath
= strdup (cmd
);
228 new_file
= fopen (cmdpath
, "w");
229 if (new_file
== NULL
)
231 fprintf (stderr
, GTXT ("Unable to open file: %s"), cmdpath
);
237 if (set_file
&& (set_file
!= stdout
))
245 er_src::proc_cmd (CmdType cmd_type
, bool first
, char *arg1
,
246 const char *arg2
, const char *arg3
)
255 dbev
->set_view_mode (VMODE_USER
);
256 print_anno_file (arg1
, arg2
, arg3
, false,
257 stdout
, stdin
, out_file
, dbev
, false);
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);
267 set_outfile (arg1
, out_file
);
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"));
276 fprintf (out_file
, GTXT (" Address Size Name\n\n"));
278 Vec_loop (Module
*, lo
->seg_modules
, mindex
, module
)
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
)
286 fprintf (out_file
, fmt
,
287 (ull_t
) fitem
->img_offset
,
294 lo
->functions
->sort (FuncAddrCmp
);
295 print_header (first
, GTXT ("Dump functions\n"));
296 lo
->dump_functions (out_file
);
300 status
= dbev
->proc_compcom (arg1
, true, false);
301 if (status
!= CMD_OK
)
302 fprintf (stderr
, GTXT ("Error: %s"), Command::get_err_string (status
));
305 status
= dbev
->proc_compcom (arg1
, false, false);
306 if (status
!= CMD_OK
)
307 fprintf (stderr
, GTXT ("Error: %s"), Command::get_err_string (status
));
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
);
321 if (out_file
!= stdout
)
323 Application::print_version_info ();
325 fprintf (out_file, "GNU %s version %s\n", get_basename (prog_name), VERSION);
329 fprintf (stderr
, GTXT ("Invalid option"));
335 er_src::run_args (int argc
, char *argv
[])
338 int arg_count
, cparam
;
347 for (int i
= 1; i
< argc
; i
++)
354 dbev
->set_view_mode (VMODE_USER
);
355 print_header (first
, GTXT ("Annotated source\n"));
356 Vec_loop (Module
*, lo
->seg_modules
, mindex
, module
)
358 if ((module
->flags
& MOD_FLAG_UNKNOWN
) != 0 ||
359 module
->lang_code
== Sp_lang_unknown
)
362 fprintf (out_file
, "\n");
363 print_anno_file (module
->file_name
, "1", NULL
, false,
364 stdout
, stdin
, out_file
, dbev
, false);
370 if (strncmp (argv
[i
], NTXT ("--whoami="), 9) == 0)
372 whoami
= argv
[i
] + 9;
375 switch (cmd_type
= Command::get_command (argv
[i
] + 1, arg_count
, cparam
))
382 if (i
>= argc
|| argv
[i
] == NULL
||
383 (*(argv
[i
]) == '-' && atoi (argv
[i
]) != -1) || i
+ 1 == argc
)
392 if (*(argv
[i
]) == '-' && atoi (argv
[i
]) == -1 &&
393 streq (arg
, NTXT ("all")))
396 if (cmd_type
== SOURCE
)
397 print_header (first
, GTXT ("Annotated source\n"));
399 print_header (first
, GTXT ("Annotated disassembly\n"));
400 Vec_loop (Module
*, lo
->seg_modules
, mindex
, module
)
402 if ((module
->flags
& MOD_FLAG_UNKNOWN
) != 0 ||
403 module
->lang_code
== Sp_lang_unknown
)
406 fprintf (out_file
, "\n");
407 proc_cmd (cmd_type
, first
, module
->file_name
, "1");
415 char *fcontext
= NULL
;
416 arg1
= parse_fname (arg
, &fcontext
);
419 fprintf (stderr
, GTXT ("Error: Invalid function/file setting: %s\n"), arg1
);
423 proc_cmd (cmd_type
, first
, arg1
, arg2
, fcontext
);
437 proc_cmd (cmd_type
, first
, (arg_count
> 0) ? argv
[i
+ 1] : NULL
,
438 (arg_count
> 1) ? argv
[i
+ 2] : NULL
);
442 if (streq (argv
[i
] + 1, NTXT ("all")) || streq (argv
[i
] + 1, NTXT ("dall")))
446 if (streq (argv
[i
] + 1, NTXT ("all")))
447 proc_cmd (FUNCS
, first
, NULL
, NULL
);
449 proc_cmd (DUMPFUNC
, first
, NULL
, NULL
);
451 print_header (first
, GTXT ("Annotated source\n"));
452 Vec_loop (Module
*, lo
->seg_modules
, mindex
, module
)
454 if ((module
->flags
& MOD_FLAG_UNKNOWN
) != 0 ||
455 module
->lang_code
== Sp_lang_unknown
)
458 fprintf (out_file
, "\n");
459 proc_cmd (SOURCE
, first
, module
->file_name
, "1");
462 print_header (first
, GTXT ("Annotated disassembly\n"));
463 Vec_loop (Module
*, lo
->seg_modules
, mindex
, module
)
465 if ((module
->flags
& MOD_FLAG_UNKNOWN
) != 0 ||
466 module
->lang_code
== Sp_lang_unknown
)
469 fprintf (out_file
, "\n");
470 proc_cmd (DISASM
, first
, module
->file_name
, "1");
476 proc_cmd (cmd_type
, first
, (arg_count
> 0) ? argv
[i
+ 1] : NULL
,
477 (arg_count
> 1) ? argv
[i
+ 2] : NULL
);
486 er_src::check_args (int argc
, char *argv
[])
488 CmdType cmd_type
= UNKNOWN_CMD
;
489 int arg_count
, cparam
;
496 // If any comments from the .rc files, log them to stderr
497 Emsg
* rcmsg
= fetch_comments ();
498 while (rcmsg
!= NULL
)
500 fprintf (stderr
, "%s: %s\n", prog_name
, rcmsg
->get_msg ());
504 // Parsing the command line
507 for (i
= 1; i
< argc
; i
++)
516 if (argc
== 3) // er_src exe file
519 else if (v_opt
&& !multiple
&& !exe
&& !str_compcom
) // just er_src -V
521 if (argc
< i
+ 1 || argc
> i
+ 3)
529 switch (cmd_type
= Command::get_command (argv
[i
] + 1, arg_count
, cparam
))
532 whoami
= argv
[i
] + 1 + cparam
;
543 Application::print_version_info ();
545 printf ("GNU %s version %s\n", get_basename (prog_name), VERSION);
556 if (i
>= argc
|| argv
[i
] == NULL
||
557 (*(argv
[i
]) == '-' && atoi (argv
[i
]) != -1) || (i
+ 1 == argc
))
575 if (!(streq (argv
[i
] + 1, NTXT ("all")) ||
576 streq (argv
[i
] + 1, NTXT ("dall"))))
578 fprintf (stderr
, "Error: invalid option: `%s'\n", argv
[i
]);
583 if (!exe
&& !(argc
== 2 && cmd_type
== VERSION_cmd
))
589 er_src::checkJavaClass (char* exe
)
591 unsigned char cf_buf
[4];
592 unsigned int magic_number
;
593 int fd
= ::open (exe
, O_RDONLY
| O_LARGEFILE
);
596 if (sizeof (cf_buf
) == read_from_file (fd
, cf_buf
, sizeof (cf_buf
)))
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
;
609 er_src::print_header (bool first
, const char* text
)
612 fprintf (out_file
, "\n");
615 fprintf (out_file
, NTXT ("%s"), text
);
616 fprintf (out_file
, "---------------------------------------\n");
621 er_src::dump_annotated (char *name
, char *sel
, char *src
, DbeView
*dbevr
,
622 bool is_dis
, bool first
)
627 print_header (first
, (is_dis
) ? ((is_java_class ()) ?
628 GTXT ("Annotated bytecode\n") :
629 GTXT ("Annotated disassembly\n")) :
630 GTXT ("Annotated source\n"));
634 Vec_loop (Module
*, lo
->seg_modules
, mindex
, module
)
636 if ((module
->flags
& MOD_FLAG_UNKNOWN
) != 0 ||
637 (!is_dis
&& module
->lang_code
== Sp_lang_unknown
))
640 fprintf (out_file
, "\n");
641 print_anno_file (module
->file_name
, sel
, src
, is_dis
,
642 stdout
, stdin
, out_file
, dbevr
, false);
647 print_anno_file (name
, sel
, src
, is_dis
, stdout
, stdin
, out_file
, dbevr
, false);
651 isFatal (bool isDisasm
, LoadObject::Arch_status status
)
657 // non-fatal errors for disassembly
658 case LoadObject::ARCHIVE_BAD_STABS
:
659 case LoadObject::ARCHIVE_NO_STABS
:
669 er_src::open (char *exe
)
671 LoadObject::Arch_status status
;
674 Vector
<Histable
*> *module_lst
;
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 ()))
681 fprintf (stderr
, GTXT ("%s: Error: unable to open file %s\n"), prog_name
, lo
->dbeFile
->get_name ());
684 checkJavaClass (exe
);
686 if (is_java_class ())
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
)
697 Emsg
*emsg
= module
->get_error ();
700 fprintf (stderr
, GTXT ("%s: Error: %s\n"), prog_name
, emsg
->get_msg ());
703 fprintf (stderr
, GTXT ("%s: Error: Could not read class file `%s'\n"), prog_name
, exe
);
706 status
= lo
->sync_read_stabs ();
707 if (status
!= LoadObject::ARCHIVE_SUCCESS
)
709 if (status
== LoadObject::ARCHIVE_ERR_OPEN
)
711 fprintf (stderr
, GTXT ("%s: Error: Could not read class file `%s'\n"), prog_name
, exe
);
717 if (status
== LoadObject::ARCHIVE_NO_STABS
)
719 fprintf (stderr
, GTXT ("%s: Error: `%s' is interface; disassembly annotation not available\n"), prog_name
, exe
);
727 status
= lo
->sync_read_stabs ();
728 if (status
!= LoadObject::ARCHIVE_SUCCESS
)
730 errstr
= lo
->status_str (status
);
733 fprintf (stderr
, "%s: %s\n", prog_name
, errstr
);
736 if (isFatal (isDisasm
, status
))
739 obj_type
= OT_EXE_ELF
;
741 // if .o file, then set file as the exe name
742 if (lo
->is_relocatable ())
744 // find the module, if we can
745 module_lst
= new Vector
<Histable
*>;
746 module
= dbeSession
->map_NametoModule (path
, module_lst
, 0);
748 // Create a module with the right name
749 module
= dbeSession
->createModule (lo
, path
);