[binutils-gdb] gprofng: fix display gmon option error handling

Claudiu Zissulescu claziss@sourceware.org
Wed Mar 11 12:59:54 GMT 2026


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=f358a184bbecbc24b6c76910a587d28b2087b9a5

commit f358a184bbecbc24b6c76910a587d28b2087b9a5
Author: Claudiu Zissulescu <claudiu.zissulescu-ianculescu@oracle.com>
Date:   Fri Mar 6 12:20:52 2026 +0200

    gprofng: fix display gmon option error handling
    
    Parse display gmon options only once so invalid arguments are not
    reported twice and exit status is set to failure for invalid usage.
    
    Also add tests in gp-gmon.exp to verify unknown options and missing
    -o argument fail as expected and produce a single diagnostic.
    
    gprofng/
            * src/gp-gmon.cc (usage_and_exit): New function.
            (check_mods): Change number of parameters.
            (checkflagterm): Fix error text, update to use new functions.
            * testsuite/gprofng.display/gp-gmon.exp: Add new test.

Diff:
---
 gprofng/src/gp-gmon.cc                        | 32 +++++++++++++--------------
 gprofng/testsuite/gprofng.display/gp-gmon.exp | 30 +++++++++++++++++++++++++
 2 files changed, 45 insertions(+), 17 deletions(-)

diff --git a/gprofng/src/gp-gmon.cc b/gprofng/src/gp-gmon.cc
index 6e018603c42..d3b4a67f51c 100644
--- a/gprofng/src/gp-gmon.cc
+++ b/gprofng/src/gp-gmon.cc
@@ -56,7 +56,8 @@ public:
 private:
   // override methods in base class
   void usage ();
-  int check_mods (int argc, char *argv[], bool check);
+  void usage_and_exit (int exit_code);
+  int check_mods (int argc, char *argv[]);
 
   bool overwrite = false;
   Coll_Ctrl *cc;
@@ -544,7 +545,7 @@ checkflagterm (const char *c)
 {
   if (c[2] != 0)
     {
-      dbe_write (2, GTXT ("collect: unrecognized argument `%s'\n"), c);
+      dbe_write (2, GTXT ("gmon: unrecognized argument `%s'\n"), c);
       return -1;
     }
   return 0;
@@ -598,14 +599,12 @@ er_gmon::start (int argc, char *argv[])
     {
       /* only one argument, -h */
       usage ();
-      exit (0);
     }
   else if (argc == 2 && (strcmp (argv[1], NTXT ("-help")) == 0 ||
 			 strcmp (argv[1], NTXT ("--help")) == 0))
     {
       /* only one argument, -help or --help */
       usage ();
-      exit (0);
     }
   else if ((argc == 2) &&
 	   (strcmp (argv[1], NTXT ("--version")) == 0))
@@ -617,12 +616,10 @@ er_gmon::start (int argc, char *argv[])
       exit (0);
     }
 
-  check_mods (argc, argv, true);
-  int adj = check_mods (argc, argv, false);
+  int adj = check_mods (argc, argv);
   if (adj < 0)
     {
-      usage ();
-      exit (0);
+      usage_and_exit (1);
     }
 
   char *ret = cc->create_exp_dir ();
@@ -651,8 +648,7 @@ er_gmon::start (int argc, char *argv[])
     }
   else if (argc != adj)
     {
-      usage ();
-      exit (0);
+      usage_and_exit (1);
     }
 
   /* Read the elf syms and the gmon file.  */
@@ -676,7 +672,7 @@ er_gmon::start (int argc, char *argv[])
 
 /* Get the args and search for modifiers.  */
 int
-er_gmon::check_mods (int argc, char *argv[], bool check)
+er_gmon::check_mods (int argc, char *argv[])
 {
   char *expName = NULL;
   int i = -1;
@@ -692,8 +688,6 @@ er_gmon::check_mods (int argc, char *argv[], bool check)
 	  overwrite = true;
 	  //FALLTHROU
 	case 'o':
-	  if (check)
-	    return i;
 	  if (checkflagterm (argv[i]) == -1)
 	    return -1;
 	  if (argv[i + 1] == NULL)
@@ -718,8 +712,6 @@ er_gmon::check_mods (int argc, char *argv[], bool check)
 	  return -1;
 	}
     }
-  if (check)
-    return i;
   if (expName)
     {
       char *ccret;
@@ -736,11 +728,17 @@ er_gmon::check_mods (int argc, char *argv[], bool check)
 	  return -1;
 	}
     }
-  return (check ? -1 : i);
+  return i;
 }
 
 void
 er_gmon::usage ()
+{
+  usage_and_exit (0);
+}
+
+void
+er_gmon::usage_and_exit (int exit_code)
 {
   printf ( GTXT (
     "Usage: gprofng display gmon [OPTION(S)] [TARGET-OBJECT [GMON-FILE]]\n"));
@@ -760,7 +758,7 @@ er_gmon::usage ()
     "                    existing experiment directory with the same name.\n"
     "\n"));
 
-    exit (0);
+    exit (exit_code);
 }
 
 er_gmon::~er_gmon ()
diff --git a/gprofng/testsuite/gprofng.display/gp-gmon.exp b/gprofng/testsuite/gprofng.display/gp-gmon.exp
index c7d261883d5..439270d83e7 100644
--- a/gprofng/testsuite/gprofng.display/gp-gmon.exp
+++ b/gprofng/testsuite/gprofng.display/gp-gmon.exp
@@ -50,6 +50,23 @@ proc check_gp_gmon { a_opt } {
   }
 }
 
+proc check_gp_gmon_fail { cmd err_pat } {
+  global tdir
+  set output [run_native_host_cmd "$cmd"]
+  set out [lindex $output 1]
+  if { [lindex $output 0] == 0 } then {
+    send_log "'$cmd' should fail, but exited with status 0\n"
+    fail $tdir
+    return -code break
+  }
+  if { ![regexp -- $err_pat $out] } then {
+    send_log "'$cmd' failed, but expected pattern '$err_pat' is missing\n"
+    fail $tdir
+    return -code break
+  }
+  return $output
+}
+
 run_native_host_cmd "mkdir -p $tdir"
 
 # Build test, create experiment:
@@ -67,4 +84,17 @@ if { [lindex $output 0] != 0 } then {
 
 check_gp_gmon gmontst
 
+# Unknown option should fail once with one diagnostic.
+set output [check_gp_gmon_fail "$gprofng display gmon -z" \
+  {gmon: unrecognized argument `-z'}]
+if { [regexp -all -- {gmon: unrecognized argument `-z'} [lindex $output 1]] != 1 } {
+  send_log "Unexpected duplicate diagnostics for unknown option\n"
+  fail $tdir
+  return
+}
+
+# Missing argument for -o should fail.
+check_gp_gmon_fail "$gprofng display gmon -o" \
+  {Argument -o must be followed by a file name}
+
 pass $tdir


More information about the Binutils-cvs mailing list