size_t
DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict,
                                      ByteOrder byte_order)
{
    assert(!m_finalized);
#ifndef LLDB_DISABLE_PYTHON
    PythonList sets (dict.GetItemForKey("sets"));
    if (sets)
    {
        const uint32_t num_sets = sets.GetSize();
        for (uint32_t i=0; i<num_sets; ++i)
        {
            PythonString py_set_name(sets.GetItemAtIndex(i));
            ConstString set_name;
            if (py_set_name)
                set_name.SetCString(py_set_name.GetString());
            if (set_name)
            {
                RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL };
                m_sets.push_back (new_set);
            }
            else
            {
                Clear();
                return 0;
            }
        }
        m_set_reg_nums.resize(m_sets.size());
    }
    PythonList regs (dict.GetItemForKey("registers"));
    if (regs)
    {
        const uint32_t num_regs = regs.GetSize();
        PythonString name_pystr("name");
        PythonString altname_pystr("alt-name");
        PythonString bitsize_pystr("bitsize");
        PythonString offset_pystr("offset");
        PythonString encoding_pystr("encoding");
        PythonString format_pystr("format");
        PythonString set_pystr("set");
        PythonString gcc_pystr("gcc");
        PythonString dwarf_pystr("dwarf");
        PythonString generic_pystr("generic");
        PythonString slice_pystr("slice");
        PythonString composite_pystr("composite");
        PythonString invalidate_regs_pystr("invalidate-regs");
        
//        typedef std::map<std::string, std::vector<std::string> > InvalidateNameMap;
//        InvalidateNameMap invalidate_map;
        for (uint32_t i=0; i<num_regs; ++i)
        {
            PythonDictionary reg_info_dict(regs.GetItemAtIndex(i));
            if (reg_info_dict)
            {
                // { 'name':'rcx'       , 'bitsize' :  64, 'offset' :  16, 'encoding':'uint'  , 'format':'hex'         , 'set': 0, 'gcc' : 2, 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', },
                RegisterInfo reg_info;
                std::vector<uint32_t> value_regs;
                std::vector<uint32_t> invalidate_regs;
                bzero (&reg_info, sizeof(reg_info));
                
                reg_info.name = ConstString (reg_info_dict.GetItemForKeyAsString(name_pystr)).GetCString();
                if (reg_info.name == NULL)
                {
                    Clear();
                    return 0;
                }
                    
                reg_info.alt_name = ConstString (reg_info_dict.GetItemForKeyAsString(altname_pystr)).GetCString();
                
                reg_info.byte_offset = reg_info_dict.GetItemForKeyAsInteger(offset_pystr, UINT32_MAX);

                if (reg_info.byte_offset == UINT32_MAX)
                {
                    // No offset for this register, see if the register has a value expression
                    // which indicates this register is part of another register. Value expressions
                    // are things like "rax[31:0]" which state that the current register's value
                    // is in a concrete register "rax" in bits 31:0. If there is a value expression
                    // we can calculate the offset
                    bool success = false;
                    const char *slice_cstr = reg_info_dict.GetItemForKeyAsString(slice_pystr);
                    if (slice_cstr)
                    {
                        // Slices use the following format:
                        //  REGNAME[MSBIT:LSBIT]
                        // REGNAME - name of the register to grab a slice of
                        // MSBIT - the most significant bit at which the current register value starts at
                        // LSBIT - the least significant bit at which the current register value ends at
                        static RegularExpression g_bitfield_regex("([A-Za-z_][A-Za-z0-9_]*)\\[([0-9]+):([0-9]+)\\]");
                        RegularExpression::Match regex_match(3);
                        if (g_bitfield_regex.Execute(slice_cstr, &regex_match))
                        {
                            llvm::StringRef reg_name_str;
                            std::string msbit_str;
                            std::string lsbit_str;
                            if (regex_match.GetMatchAtIndex(slice_cstr, 1, reg_name_str) &&
                                regex_match.GetMatchAtIndex(slice_cstr, 2, msbit_str) &&
                                regex_match.GetMatchAtIndex(slice_cstr, 3, lsbit_str))
                            {
                                const uint32_t msbit = Args::StringToUInt32(msbit_str.c_str(), UINT32_MAX);
                                const uint32_t lsbit = Args::StringToUInt32(lsbit_str.c_str(), UINT32_MAX);
                                if (msbit != UINT32_MAX && lsbit != UINT32_MAX)
                                {
                                    if (msbit > lsbit)
                                    {
                                        const uint32_t msbyte = msbit / 8;
                                        const uint32_t lsbyte = lsbit / 8;

                                        ConstString containing_reg_name(reg_name_str);
                                        
                                        RegisterInfo *containing_reg_info = GetRegisterInfo (containing_reg_name);
                                        if (containing_reg_info)
                                        {
                                            const uint32_t max_bit = containing_reg_info->byte_size * 8;
                                            if (msbit < max_bit && lsbit < max_bit)
                                            {
                                                m_invalidate_regs_map[containing_reg_info->kinds[eRegisterKindLLDB]].push_back(i);
                                                m_value_regs_map[i].push_back(containing_reg_info->kinds[eRegisterKindLLDB]);
                                                m_invalidate_regs_map[i].push_back(containing_reg_info->kinds[eRegisterKindLLDB]);
                                                
                                                if (byte_order == eByteOrderLittle)
                                                {
                                                    success = true;
                                                    reg_info.byte_offset = containing_reg_info->byte_offset + lsbyte;
                                                }
                                                else if (byte_order == eByteOrderBig)
                                                {
                                                    success = true;
                                                    reg_info.byte_offset = containing_reg_info->byte_offset + msbyte;
                                                }
                                                else
                                                {
                                                    assert(!"Invalid byte order");
                                                }
                                            }
                                            else
                                            {
                                                if (msbit > max_bit)
                                                    printf("error: msbit (%u) must be less than the bitsize of the register (%u)\n", msbit, max_bit);
                                                else
                                                    printf("error: lsbit (%u) must be less than the bitsize of the register (%u)\n", lsbit, max_bit);
                                            }
                                        }
                                        else
                                        {
                                            printf("error: invalid concrete register \"%s\"\n", containing_reg_name.GetCString());
                                        }
                                    }
                                    else
                                    {
                                        printf("error: msbit (%u) must be greater than lsbit (%u)\n", msbit, lsbit);
                                    }
                                }
                                else
                                {
                                    printf("error: msbit (%u) and lsbit (%u) must be valid\n", msbit, lsbit);
                                }
                            }
                            else
                            {
                                // TODO: print error invalid slice string that doesn't follow the format
                                printf("error: failed to extract regex matches for parsing the register bitfield regex\n");

                            }
                        }
                        else
                        {
                            // TODO: print error invalid slice string that doesn't follow the format
                            printf("error: failed to match against register bitfield regex\n");
                        }
                    }
                    else
                    {
                        PythonList composite_reg_list (reg_info_dict.GetItemForKey(composite_pystr));
                        if (composite_reg_list)
                        {
                            const size_t num_composite_regs = composite_reg_list.GetSize();
                            if (num_composite_regs > 0)
                            {
                                uint32_t composite_offset = UINT32_MAX;
                                for (uint32_t composite_idx=0; composite_idx<num_composite_regs; ++composite_idx)
                                {
                                    PythonString composite_reg_name_pystr(composite_reg_list.GetItemAtIndex(composite_idx));
                                    if (composite_reg_name_pystr)
                                    {
                                        ConstString composite_reg_name(composite_reg_name_pystr.GetString());
                                        if (composite_reg_name)
                                        {
                                            RegisterInfo *composite_reg_info = GetRegisterInfo (composite_reg_name);
                                            if (composite_reg_info)
                                            {
                                                if (composite_offset > composite_reg_info->byte_offset)
                                                    composite_offset = composite_reg_info->byte_offset;
                                                m_value_regs_map[i].push_back(composite_reg_info->kinds[eRegisterKindLLDB]);
                                                m_invalidate_regs_map[composite_reg_info->kinds[eRegisterKindLLDB]].push_back(i);
                                                m_invalidate_regs_map[i].push_back(composite_reg_info->kinds[eRegisterKindLLDB]);
                                            }
                                            else
                                            {
                                                // TODO: print error invalid slice string that doesn't follow the format
                                                printf("error: failed to find composite register by name: \"%s\"\n", composite_reg_name.GetCString());
                                            }
                                        }
                                        else
                                        {
                                            printf("error: 'composite' key contained an empty string\n");
                                        }
                                    }
                                    else
                                    {
                                        printf("error: 'composite' list value wasn't a python string\n");
                                    }
                                }
                                if (composite_offset != UINT32_MAX)
                                {
                                    reg_info.byte_offset = composite_offset;
                                    success = m_value_regs_map.find(i) != m_value_regs_map.end();
                                }
                                else
                                {
                                    printf("error: 'composite' registers must specify at least one real register\n");
                                }
                            }
                            else
                            {
                                printf("error: 'composite' list was empty\n");
                            }
                        }
                    }
                    
                    
                    if (!success)
                    {
                        Clear();
                        return 0;
                    }
                }
                const int64_t bitsize = reg_info_dict.GetItemForKeyAsInteger(bitsize_pystr, 0);
                if (bitsize == 0)
                {
                    Clear();
                    return 0;
                }

                reg_info.byte_size =  bitsize / 8;
                
                const char *format_cstr = reg_info_dict.GetItemForKeyAsString(format_pystr);
                if (format_cstr)
                {
                    if (Args::StringToFormat(format_cstr, reg_info.format, NULL).Fail())
                    {
                        Clear();
                        return 0;
                    }
                }
                else
                {
                    reg_info.format = (Format)reg_info_dict.GetItemForKeyAsInteger (format_pystr, eFormatHex);
                }
                
                const char *encoding_cstr = reg_info_dict.GetItemForKeyAsString(encoding_pystr);
                if (encoding_cstr)
                    reg_info.encoding = Args::StringToEncoding (encoding_cstr, eEncodingUint);
                else
                    reg_info.encoding = (Encoding)reg_info_dict.GetItemForKeyAsInteger (encoding_pystr, eEncodingUint);

                const int64_t set = reg_info_dict.GetItemForKeyAsInteger(set_pystr, -1);
                if (set >= m_sets.size())
                {
                    Clear();
                    return 0;
                }

                // Fill in the register numbers
                reg_info.kinds[lldb::eRegisterKindLLDB]    = i;
                reg_info.kinds[lldb::eRegisterKindGDB]     = i;
                reg_info.kinds[lldb::eRegisterKindGCC]     = reg_info_dict.GetItemForKeyAsInteger(gcc_pystr, LLDB_INVALID_REGNUM);
                reg_info.kinds[lldb::eRegisterKindDWARF]   = reg_info_dict.GetItemForKeyAsInteger(dwarf_pystr, LLDB_INVALID_REGNUM);
                const char *generic_cstr = reg_info_dict.GetItemForKeyAsString(generic_pystr);
                if (generic_cstr)
                    reg_info.kinds[lldb::eRegisterKindGeneric] = Args::StringToGenericRegister (generic_cstr);
                else
                    reg_info.kinds[lldb::eRegisterKindGeneric] = reg_info_dict.GetItemForKeyAsInteger(generic_pystr, LLDB_INVALID_REGNUM);

                // Check if this register invalidates any other register values when it is modified
                PythonList invalidate_reg_list (reg_info_dict.GetItemForKey(invalidate_regs_pystr));
                if (invalidate_reg_list)
                {
                    const size_t num_regs = invalidate_reg_list.GetSize();
                    if (num_regs > 0)
                    {
                        for (uint32_t idx=0; idx<num_regs; ++idx)
                        {
                            PythonObject invalidate_reg_object (invalidate_reg_list.GetItemAtIndex(idx));
                            PythonString invalidate_reg_name_pystr(invalidate_reg_object);
                            if (invalidate_reg_name_pystr)
                            {
                                ConstString invalidate_reg_name(invalidate_reg_name_pystr.GetString());
                                if (invalidate_reg_name)
                                {
                                    RegisterInfo *invalidate_reg_info = GetRegisterInfo (invalidate_reg_name);
                                    if (invalidate_reg_info)
                                    {
                                        m_invalidate_regs_map[i].push_back(invalidate_reg_info->kinds[eRegisterKindLLDB]);
                                    }
                                    else
                                    {
                                        // TODO: print error invalid slice string that doesn't follow the format
                                        printf("error: failed to find a 'invalidate-regs' register for \"%s\" while parsing register \"%s\"\n", invalidate_reg_name.GetCString(), reg_info.name);
                                    }
                                }
                                else
                                {
                                    printf("error: 'invalidate-regs' list value was an empty string\n");
                                }
                            }
                            else
                            {
                                PythonInteger invalidate_reg_num(invalidate_reg_object);

                                if (invalidate_reg_num)
                                {
                                    const int64_t r = invalidate_reg_num.GetInteger();
                                    if (r != UINT64_MAX)
                                        m_invalidate_regs_map[i].push_back(r);
                                    else
                                        printf("error: 'invalidate-regs' list value wasn't a valid integer\n");
                                }
                                else
                                {
                                    printf("error: 'invalidate-regs' list value wasn't a python string or integer\n");
                                }
                            }
                        }
                    }
                    else
                    {
                        printf("error: 'invalidate-regs' contained an empty list\n");
                    }
                }

                // Calculate the register offset
                const size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size;
                if (m_reg_data_byte_size < end_reg_offset)
                    m_reg_data_byte_size = end_reg_offset;

                m_regs.push_back (reg_info);
                m_set_reg_nums[set].push_back(i);

            }
            else
            {
                Clear();
                return 0;
            }
        }
        Finalize ();
    }
#endif
    return m_regs.size();
}
size_t
DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict)
{
#ifndef LLDB_DISABLE_PYTHON
    PythonList sets (dict.GetItemForKey("sets"));
    if (sets)
    {
        const uint32_t num_sets = sets.GetSize();
        for (uint32_t i=0; i<num_sets; ++i)
        {
            PythonString py_set_name(sets.GetItemAtIndex(i));
            ConstString set_name;
            if (py_set_name)
                set_name.SetCString(py_set_name.GetString());
            if (set_name)
            {
                RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL };
                m_sets.push_back (new_set);
            }
            else
            {
                Clear();
                return 0;
            }
        }
        m_set_reg_nums.resize(m_sets.size());
    }
    PythonList regs (dict.GetItemForKey("registers"));
    if (regs)
    {
        const uint32_t num_regs = regs.GetSize();
        PythonString name_pystr("name");
        PythonString altname_pystr("alt-name");
        PythonString bitsize_pystr("bitsize");
        PythonString offset_pystr("offset");
        PythonString encoding_pystr("encoding");
        PythonString format_pystr("format");
        PythonString set_pystr("set");
        PythonString gcc_pystr("gcc");
        PythonString dwarf_pystr("dwarf");
        PythonString generic_pystr("generic");
        for (uint32_t i=0; i<num_regs; ++i)
        {
            PythonDictionary reg_info_dict(regs.GetItemAtIndex(i));
            if (reg_info_dict)
            {
                // { 'name':'rcx'       , 'bitsize' :  64, 'offset' :  16, 'encoding':'uint'  , 'format':'hex'         , 'set': 0, 'gcc' : 2, 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', },
                RegisterInfo reg_info;
                bzero (&reg_info, sizeof(reg_info));
                
                reg_info.name = ConstString (reg_info_dict.GetItemForKeyAsString(name_pystr)).GetCString();
                if (reg_info.name == NULL)
                {
                    Clear();
                    return 0;
                }
                    
                reg_info.alt_name = ConstString (reg_info_dict.GetItemForKeyAsString(altname_pystr)).GetCString();
                
                reg_info.byte_offset = reg_info_dict.GetItemForKeyAsInteger(offset_pystr, UINT32_MAX);

                if (reg_info.byte_offset == UINT32_MAX)
                {
                    Clear();
                    return 0;
                }
                reg_info.byte_size = reg_info_dict.GetItemForKeyAsInteger(bitsize_pystr, 0) / 8;
                
                if (reg_info.byte_size == 0)
                {
                    Clear();
                    return 0;
                }
                
                const char *format_cstr = reg_info_dict.GetItemForKeyAsString(format_pystr);
                if (format_cstr)
                {
                    if (Args::StringToFormat(format_cstr, reg_info.format, NULL).Fail())
                    {
                        Clear();
                        return 0;
                    }
                }
                else
                    reg_info.format = eFormatHex;
                    
                const char *encoding_cstr = reg_info_dict.GetItemForKeyAsString(encoding_pystr);
                if (encoding_cstr)
                    reg_info.encoding = Args::StringToEncoding (encoding_cstr, eEncodingUint);
                else
                    reg_info.encoding = eEncodingUint;

                const int64_t set = reg_info_dict.GetItemForKeyAsInteger(set_pystr, -1);
                if (set >= m_sets.size())
                {
                    Clear();
                    return 0;
                }

                reg_info.kinds[lldb::eRegisterKindLLDB]    = i;
                reg_info.kinds[lldb::eRegisterKindGDB]     = i;
                reg_info.kinds[lldb::eRegisterKindGCC]     = reg_info_dict.GetItemForKeyAsInteger(gcc_pystr, LLDB_INVALID_REGNUM);
                reg_info.kinds[lldb::eRegisterKindDWARF]   = reg_info_dict.GetItemForKeyAsInteger(dwarf_pystr, LLDB_INVALID_REGNUM);
                reg_info.kinds[lldb::eRegisterKindGeneric] = Args::StringToGenericRegister (reg_info_dict.GetItemForKeyAsString(generic_pystr));
                const size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size;
                if (m_reg_data_byte_size < end_reg_offset)
                    m_reg_data_byte_size = end_reg_offset;

                m_regs.push_back (reg_info);
                m_set_reg_nums[set].push_back(i);

            }
            else
            {
                Clear();
                return 0;
            }
        }
        Finalize ();
    }
#endif
    return 0;
}