register read on 32-bit Linux

This is currently calling into the POSIX RegisterContext_x86_64 and returning all the 64-bit registers.

I’m guessing this is known already. Curious if someone is already working on this or has a plan for fixing it before I jump in?

Thanks!

Go for it, Michael!

FYI, the x86_64 build of LLDB will have limited success with i386 inferiors, but it’s a pretty good starting point (i.e. test/functionalities/registers passes). In this case, ptrace calls populate the 64-bit register set, and the RegisterContext_x86_64 class uses offsetof to associate the i386 register set with the LS bytes of the associated 64-bit registers. However, this isn’t correct because “The DWARF and GCC register numbers need to use the i386 register numbering schemes otherwise all info parsed from EH frame and DWARF will be incorrect when they don’t match up. – Greg Clayton”.

The i386 build of LLDB should use RegisterContext_i386. Similarly, a future remote i386 target should use RegisterContext_i386. However, this class is just stubbed in.

An eventual goal is to abstract a dynamic register set that can be used consistently for native local and remote debugging in a platform-independent manner. Also, for core file support across platforms, we’ll want a register set hierarchy that is distinct from platform dependencies like ProcessMonitor. This was implemented for MachO, and Greg provided a skeleton patch for this purpose on the lists. Cheers,

  • Ashok

An eventual goal is to abstract a dynamic register set that can be used consistently for native local and remote debugging in a platform-independent manner. Also, for core file support across platforms, we’ll want a register set hierarchy that is distinct from platform dependencies like ProcessMonitor.

Does it make sense for me to tackle this right now instead of making what I assume would be temporary fixes to RegisterContext_x86_64? I assume doing the larger correct fix would take care of Greg’s other concerns as well? Ie, this: “The DWARF and GCC register numbers need to use the i386 register numbering schemes otherwise all info parsed from EH frame and DWARF will be incorrect when they don’t match up. – Greg Clayton”.

Greg provided a skeleton patch for this purpose on the lists.

Does anyone have a pointer to this? I poked around a bit didn’t find it.

For what it’s worth, our most common use case is 64-bit build of LLDB debugging i386 targets with some debugging of 64-bit apps using a 64-bit LLDB build. (Ie, debugging lldb with lldb).

Thanks.
-Mike

An eventual goal is to abstract a dynamic register set that can be used consistently for native local and remote debugging in a platform-independent manner. Also, for core file support across platforms, we’ll want a register set hierarchy that is distinct from platform dependencies like ProcessMonitor.

Does it make sense for me to tackle this right now instead of making what I assume would be temporary fixes to RegisterContext_x86_64? I assume doing the larger correct fix would take care of Greg's other concerns as well? Ie, this: “The DWARF and GCC register numbers need to use the i386 register numbering schemes otherwise all info parsed from EH frame and DWARF will be incorrect when they don't match up. – Greg Clayton”.

Greg provided a skeleton patch for this purpose on the lists.

Does anyone have a pointer to this? I poked around a bit didn't find it.

Just take a look at RegisterContextDarwin_x86_64 as an example. It is a register context with the exact register structures laid out as they exist in Darwin builds. There are then 6 pure virtual functions:

    // Subclasses override these to do the actual reading.
    virtual int
    DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) = 0;
    
    virtual int
    DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0;
    
    virtual int
    DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0;
    
    virtual int
    DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
    
    virtual int
    DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
    
    virtual int
    DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0;

Then RegisterContextKDP_x86_64 and RegisterContextDarwin_x86_64_Mach subclass this register context to provide the reading and writing.

The current RegisterContext_x86_64 class includes references to ProcessMonitor with "ProcessMonitor &GetMonitor();" which is not correct. You need a base classes for each flavor of register (x86_64 and i386) that contains the exact data structures, then have subclasses for the native debugging where the ProcessMonitor is used to do the reading/writing (via pure virtual functions like RegisterContextDarwin_x86_64), then another one for core files. The x86_64 shouldn't be used for i386 even on a 64 bit machine... RegisterContext_i386 should be used and it should adjust itself to account for being run on a 64 bit machine, or there should be three classes. So the breakdown as I see it should be:

RegisterContextPOSIX_x86_64
RegisterContextPOSIX_i386

These two classes contain data only and are similar to RegisterContextDarwin_x86_64 where they have just the data structures with correct register numberings for each architecture.

Then have subclasses:

RegisterContextProcessMonitor_x86_64 (inherits from RegisterContextPOSIX_x86_64 and does reads/writes using ProcessMonitor)
RegisterContextProcessMonitor_i386 (inherits from RegisterContextPOSIX_i386 and does reads/writes using ProcessMonitor)
RegisterContextELFCore_x86_64 (inherits from RegisterContextPOSIX_x86_64 and does reads/writes from buffers from the core file)
RegisterContextELFCore_i386 (inherits from RegisterContextPOSIX_i386 and does reads/writes from buffers from the core file)

You might even want a

RegisterContextProcessMonitor_i386_64 for i386 on a 64 bit system.

For what it's worth, our most common use case is 64-bit build of LLDB debugging i386 targets with some debugging of 64-bit apps using a 64-bit LLDB build. (Ie, debugging lldb with lldb).

This is where I think the register contexts are done incorrectly in linux. The x86_64 one is doing both x86_64 and i386 on 64 bit host which is making the code messy. I think register contexts done as mentioned above would clean this all up.