1

I noticed during debugging that the optarg variable of GNU's getopt remained zero (i.e. address 0x0) during debugging. But when optarg is used as right-hand operand of assignment or passed as argument to a parameter, the expected value is applied. The example from GNU:

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main (int argc, char **argv)
{
  int aflag = 0;
  int bflag = 0;
  char *cvalue = NULL;
  int index;
  int c;

  opterr = 0;

  while ((c = getopt (argc, argv, "abc:")) != -1)
    switch (c)
      {
      case 'a':
        aflag = 1;
        break;
      case 'b':
        bflag = 1;
        break;
      case 'c':          # b 26
        cvalue = optarg; # gdb stops right before executing this line
        break;
      case '?':
        if (optopt == 'c')
          fprintf (stderr, "Option -%c requires an argument.\n", optopt);
        else if (isprint (optopt))
          fprintf (stderr, "Unknown option `-%c'.\n", optopt);
        else
          fprintf (stderr,
                   "Unknown option character `\\x%x'.\n",
                   optopt);
        return 1;
      default:
        abort ();
      }

  printf ("aflag = %d, bflag = %d, cvalue = %s\n",
          aflag, bflag, cvalue);

  for (index = optind; index < argc; index++)
    printf ("Non-option argument %s\n", argv[index]);
  return 0;
}

Usage

$ gcc -o getopt getopt.c -g # debugging ON, optimizations OFF
$ gdb getopt
(gdb) b 26 # set breakpoint
(gdb) r -cfoo
(gdb) p optarg
$1 = 0x0 # no "foo"?
(gdb) n # executes cvalue = optarg
(gdb) p cvalue
$2 = 0x7fffffffea99 "foo" # here it is, please don't expect to get the same memory-address

Why optarg doesn't contain the character string "foo" at line 26? What do I miss here?

More bewildering, I figured out it doesn't contain "foo" even after the line has been executed. I've put a glance at the original source and didn't notice something like a compiler optimization. I'm using GCC 11.1.0 on Archlinux, x86_64.

Thank you

Peter
  • 2,240
  • 3
  • 23
  • 37
  • 1
    Where, *exactly*, is your breakpoint were you examine the value of `optarg`? Please add a comment on that line in the shown code. – Some programmer dude Oct 01 '21 at 16:20
  • Please indicate which line is 26 – Useless Oct 01 '21 at 16:20
  • Also think about that while all [manual pages](https://man7.org/linux/man-pages/man3/getopt.3.html) show the `optarg` declaration as `extern char *optarg;` it may actually be implemented as a macro (just like `errno` typically is). – Some programmer dude Oct 01 '21 at 16:23
  • The debugger halts directly before executing "cvalue = optarg". At that point optarg is zero, I go ahead with 'n' and after the assignment cvalue has the the value "foo" but optarg is still zero. – Peter Oct 01 '21 at 16:28
  • 2
    @Peter -- Does your program still work? If so, then this is a debugger issue, not an issue with the program itself. – PaulMcKenzie Oct 01 '21 at 16:31
  • @PaulMcKenzie Yes. Perfectly! – Peter Oct 01 '21 at 16:32
  • @Someprogrammerdude In the original source it is defined as 'char *optarg = NULL;' you can use the link the question above, line 115. – Peter Oct 01 '21 at 16:33
  • 1
    I figured out (with tabbing) that I can see the actual value with p (char*)'optarg@GLIBC_2.2.5' $6 = 0x7fffffffea99 "foo". I found two posts about the ABI changes, but regarding C++ only: https://stackoverflow.com/questions/43575687/why-can-gdb-not-see-a-global-variable https://stackoverflow.com/questions/40820535/can-not-print-global-objects-in-gdb – Peter Oct 01 '21 at 16:52

1 Answers1

0

PaulMcKenzie seems right. It is probably this old bug 8588 within GDB. GDB struggles handling the GOT (Global-Offset-Table) right which is a part of PIC (Position-Independent-Code].

Workaround

p (char*)'optarg@GLIBC_2.2.5' 

We reference here the variable optarg and the version symbol of the GLIBC. The version 2.2.5 is the baseline which already includes provides GNU getopt and therefore the newer ones don't apply.

Thank you

Peter
  • 2,240
  • 3
  • 23
  • 37