[lldb-dev] Adding a new RegisterContext for Windows

Greg Clayton gclayton at apple.com
Mon Nov 17 17:01:02 PST 2014


> On Nov 17, 2014, at 3:59 PM, Zachary Turner <zturner at google.com> wrote:
> 
> I'm looking into adding a new RegisterContext for windows.  Virgile's patch that I was working on merging inherited from RegisterContext_POSIX, but on the surface this seems like the wrong thing to do, and I wonder if we need an entirely new one for Windows (or need to change the name of RegisterContext_POSIX to something else).
> 
> What are all the steps involved here?  From what I can tell at a minimum I need to implement a RegisterContextWindows_x86 and RegisterContextWindows_x86_64, but there's also RegisterInfoInterface and a few other things I need to figure out.
> 
> A few other specific questions:
> 1) Why is all this stuff for different platforms is in Plugins/Process/Utility, instead of in the individual process plugins like Plugins/Process/Linux, or Plugins/Process/FreeBSD?

These were being used by multiple plug-ins. FreeBSD and Linux are closely related (they use ptrace) so they can sometimes share their register contexts.

> 
> 2) Some code seems to be dead.  Like in RegisterContextPosix, there's a long list of static variables, g_contained_eax, g_invalidate_eax, etc.  But none of this stuff seems to be used for anything.  Am I overlooking something obvious?

If they are dead then remove them. Looking at the RegisterInfo struct:

    typedef struct
    {
        const char *name;        // Name of this register, can't be NULL
        const char *alt_name;    // Alternate name of this register, can be NULL
        uint32_t byte_size;      // Size in bytes of the register
        uint32_t byte_offset;    // The byte offset in the register context data where this register's value is found
        lldb::Encoding encoding; // Encoding of the register bits
        lldb::Format format;     // Default display format
        uint32_t kinds[lldb::kNumRegisterKinds]; // Holds all of the various register numbers for all register kinds
        uint32_t *value_regs;    // List of registers that must be terminated with LLDB_INVALID_REGNUM
        uint32_t *invalidate_regs; // List of registers that must be invalidated when this register is modified, list must be terminated with LLDB_INVALID_REGNUM
    } RegisterInfo;


Registers can define registers that make up the value for this register (like "d0" on ARM can say it is made up from "s0" and "s1" since "d0" is a 64 bit register). Then this register is read from, it will not issue a register read for its own register number, but it will request all registers in "value_regs" be read instead. 

Likewise, you might want to invalidate registers when this register is modified, like "eax" (if you define one in your register context) would invalidate "rax" "ax" "al" if "eax" is modified.

The static arrays seem to be left over from a copy and paste where g_contained_eax represented the register for "value_regs" or "invalidate_regs"...

> 
> 3) What is the difference between a RegisterInfoInterface and a RegisterContext?

I am not sure, this class was implemented, but it isn't referenced currently.

For register contexts you will just need to override all pure virtual functions in lldb_private::RegisterContext.


You must define all of your registers by returning a count:

    virtual size_t
    RegisterContextWindows::GetRegisterCount () = 0;

And supply a register info for each register. Register numbers are zero based index identifiers that must have no gaps. Each register must have a RegisterInfo struct that describes it:

    virtual const RegisterInfo *
    RegisterContextWindows::GetRegisterInfoAtIndex (size_t reg) = 0;


You must also describe your register sets:

    virtual size_t
    GetRegisterSetCount () = 0;

    virtual const RegisterSet *
    GetRegisterSet (size_t reg_set) = 0;

You must also be able to convert register numbers of various kinds into actual zero based register index IDs:

    virtual uint32_t
    ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) = 0;


And read and write the registers (see all remaining pure virtuals).

The common way to define your register infos is to just have a static array in your RegisterContextWindows.cpp:

static RegisterInfo g_x86_64_register_infos[] = 
{ 
	...
}


Then your RegisterContextWindows::GetRegisterInfoAtIndex() just returns

const RegisterInfo *
RegisterContextWindows::GetRegisterInfoAtIndex (size_t reg)
{
	if (reg < sizeof_array(g_x86_64_register_infos))
	    return g_x86_64_register_infos[reg];
	return NULL;
}

So there is nothing that special about the register context class, just implement the pure virtual and abstract it underneath so you have different classes for i386 and x86_64. The register context defines a bunch of bytes for all registers and the register info structs contain the byte_offset into the big data buffer that can contain all of your registers. 

Let me know if you have any questions.

Greg






More information about the lldb-dev mailing list