-5

I've got the following piece of code which failed to compile on i386 with "gs" missing. I've looked at the struct definition, and it's clearly there. Any idea what I got wrong? Thanks!

struct user_regs_struct regs_struct;
  struct iovec pt_iov = {
      .iov_base = &regs,
      .iov_len = sizeof(regs),
  };
  if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &pt_iov) == 0) {
#if defined(__x86_64__)
    return regs_struct.fs;
#elif defined(__i386__)
    return regs_struct.gs;  <<< Got an error about "gs" not being a field of user_regs_struct 
  }

P.S: I know I should produce a small test case but I could not. It didn't hit this error on a standalone app. (never mind that I don't have the hardware to test it locally). All I knew was this error popped up when the code is part of a larger system, being built remotely. That's why I was hoping maybe somebody recognized this as a "known-issue" or have some intuition as to what might be the issue.

Curious Learner
  • 343
  • 2
  • 9
  • 1
    "it's clearly there". If you say so. But how do you expect us to know whether that's the case or not since you don't show the definition of the struct? Please provide a [minimal verifiable example](https://stackoverflow.com/help/minimal-reproducible-example). There's not much we can say based on this incomplete code fragment. – kaylum Aug 07 '20 at 03:31
  • Are you compiling this on GNU/Linux? What `#include`s do you have, and what compiler command line did you use? Are you sure you used `-m32`? It's not the default on normal 64-bit systems. – Peter Cordes Aug 07 '20 at 03:32
  • Yes. that's a typo. Re: definition, this struct part of the standard linux kernel. So I assumed it could be looked up easily by anyone here – Curious Learner Aug 07 '20 at 03:42
  • We could easily look it up if the code excerpt included the include directive. – prl Aug 07 '20 at 03:46
  • Is this a kernel module? Are you using a kernel build environment? (Makefile, config, etc.) – prl Aug 07 '20 at 03:49
  • Meta comment: there’s people here who know Linux, but there’s no Linux tag nor any other indication that it’s a Linux question, so people who don’t know Linux will be totally lost, and some of us who do might not have instantly recognized it. – prl Aug 07 '20 at 03:53
  • 1
    Added the LInux tag. Didn't think about it. Sorry! So the reason I couldn't make standalone case is because I couldn't reproduce it on my machine. Only hit this error when the code is part of a larger system (and the build is on remote machine...) – Curious Learner Aug 07 '20 at 03:56
  • That's why I was hoping maybe somebody recognizes this as a "known-issue" ... – Curious Learner Aug 07 '20 at 03:57
  • Yes there was a t missing. (Fixed now) – Curious Learner Aug 07 '20 at 03:58
  • @prl: That was my reaction, too, but the `[ptrace]` tag was there from the start, and I think ptrace is Linux-specific. – Peter Cordes Aug 07 '20 at 03:59
  • @Peter, FYI, ptrace is much older than Linux. – prl Aug 07 '20 at 04:00
  • @prl: I thought other Unixes had different names for their debugging APIs, turns out you're right, for example FreeBSD calls its API `ptrace` as well so the name probably goes way back. – Peter Cordes Aug 07 '20 at 04:04
  • Looks like the i386 version of `user_regs_struct` calls it `xgs` for some reason. IDK why, but this is super obvious if you look in the header file. `ack user_regs_struct /usr/include` to find the right file, then look in `sys/user.h`. – Peter Cordes Aug 07 '20 at 04:05
  • @PeterCordes well, it's not super obvious to me where to find it for i386 ...Thanks! – Curious Learner Aug 07 '20 at 04:11
  • @Peter, my old Unix books are at my office, but I’m pretty sure ptrace was in BSD 4.1 in 1983. – prl Aug 07 '20 at 04:15
  • Ok, "super obvious" was a bit too strong a statement, but I assumed there'd be either separate 32 and 64 files like `unistd_32.h`, or an ifdef, because 32-bit Linux wouldn't have a struct with room for x86-64 regs. So after finding the file that defined the struct (which was trivial with a `grep -r` or `ack`), the file turned out to be small, and the struct name is long and thus only occurs twice. Or you could just compile your file with `-E` and look at the preprocessor output. All of these steps seem obvious to me, and turned out to be easier than I expected. But now you know for next time – Peter Cordes Aug 07 '20 at 04:18

1 Answers1

1

Looks like the i386 version of user_regs_struct calls it xgs for some reason.

In sys/user.h, there's an #ifdef __x86_64__. The #else /* These are the 32-bit x86 structures. */ side of the file has this content:

struct user_regs_struct
{
  long int ebx;
  long int ecx;
  long int edx;
  long int esi;
  long int edi;
  long int ebp;
  long int eax;
  long int xds;
  long int xes;
  long int xfs;
  long int xgs;
  long int orig_eax;
  long int eip;
  long int xcs;
  long int eflags;
  long int esp;
  long int xss;
};

Perhaps that changed in some glibc version? This is on x86-64 Arch GNU/Linux, so those are plain vanilla glibc headers (taken from the Linux kernel).

ack user_regs_struct /usr/include found the right file right away. (like grep -r).

Note the top of the file says:

/* The whole purpose of this file is for GDB and GDB only.  Don't read
   too much into it.  Don't use it for anything other than GDB unless
   you know what you are doing.  */

I don't know exactly why there's such a stern warning, or if they really mean for ptrace in general. If it's more than that, I'd be cautious about using it blindly if reading the header and checking the struct member names wasn't obvious to you. Maybe it's fine, maybe it's not, just saying that I wouldn't rely on code you write using it for anything critical without more research.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847