root/src/kits/debugger/dwarf/AttributeClasses.cpp
/*
 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Copyright 2013-2018, Rene Gollent, rene@gollent.com.
 * Distributed under the terms of the MIT License.
 */

#include "AttributeClasses.h"
#include "Dwarf.h"


enum {
        AC_ADDRESS              = 1 << (ATTRIBUTE_CLASS_ADDRESS - 1),
        AC_ADDRPTR              = 1 << (ATTRIBUTE_CLASS_ADDRPTR - 1),
        AC_BLOCK                = 1 << (ATTRIBUTE_CLASS_BLOCK - 1),
        AC_CONSTANT             = 1 << (ATTRIBUTE_CLASS_CONSTANT - 1),
        AC_FLAG                 = 1 << (ATTRIBUTE_CLASS_FLAG - 1),
        AC_LINEPTR              = 1 << (ATTRIBUTE_CLASS_LINEPTR - 1),
        AC_LOCLIST      = 1 << (ATTRIBUTE_CLASS_LOCLIST - 1),
        AC_LOCLISTPTR   = 1 << (ATTRIBUTE_CLASS_LOCLISTPTR - 1),
        AC_MACPTR               = 1 << (ATTRIBUTE_CLASS_MACPTR - 1),
        AC_RANGELIST    = 1 << (ATTRIBUTE_CLASS_RANGELIST - 1),
        AC_RANGELISTPTR = 1 << (ATTRIBUTE_CLASS_RANGELISTPTR - 1),
        AC_REFERENCE    = 1 << (ATTRIBUTE_CLASS_REFERENCE - 1),
        AC_STRING               = 1 << (ATTRIBUTE_CLASS_STRING - 1),
        AC_STROFFSETSPTR= 1 << (ATTRIBUTE_CLASS_STROFFSETSPTR - 1),
};


struct attribute_info_entry {
        const char*     name;
        uint16          value;
        uint16          classes;
};

struct attribute_name_info_entry {
        const char*                             name;
        DebugInfoEntrySetter    setter;
        uint16                                  value;
        uint16                                  classes;
};


#undef ENTRY
#define ENTRY(name)     "DW_AT_" #name, &DebugInfoEntry::AddAttribute_##name, \
        DW_AT_##name

static const attribute_name_info_entry kAttributeNameInfos[] = {
        { ENTRY(sibling),                               AC_REFERENCE },
        { ENTRY(location),                              AC_BLOCK | AC_LOCLIST },
        { ENTRY(name),                                  AC_STRING },
        { ENTRY(ordering),                              AC_CONSTANT },
        { ENTRY(byte_size),                             AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
        { ENTRY(bit_offset),                    AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
        { ENTRY(bit_size),                              AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
        { ENTRY(stmt_list),                             AC_LINEPTR },
        { ENTRY(low_pc),                                AC_ADDRESS | AC_CONSTANT | AC_REFERENCE },
        { ENTRY(high_pc),                               AC_ADDRESS | AC_CONSTANT | AC_REFERENCE },
        { ENTRY(language),                              AC_CONSTANT },
        { ENTRY(discr),                                 AC_REFERENCE },
        { ENTRY(discr_value),                   AC_CONSTANT },
        { ENTRY(visibility),                    AC_CONSTANT },
        { ENTRY(import),                                AC_REFERENCE },
        { ENTRY(string_length),                 AC_BLOCK | AC_LOCLIST },
        { ENTRY(common_reference),              AC_REFERENCE },
        { ENTRY(comp_dir),                              AC_STRING },
        { ENTRY(const_value),                   AC_BLOCK | AC_CONSTANT | AC_STRING },
        { ENTRY(containing_type),               AC_REFERENCE },
        { ENTRY(default_value),                 AC_REFERENCE | AC_CONSTANT | AC_FLAG },
        { ENTRY(inline),                                AC_CONSTANT },
        { ENTRY(is_optional),                   AC_FLAG },
        { ENTRY(lower_bound),                   AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
        { ENTRY(producer),                              AC_STRING },
        { ENTRY(prototyped),                    AC_FLAG },
        { ENTRY(return_addr),                   AC_BLOCK | AC_LOCLIST },
        { ENTRY(start_scope),                   AC_CONSTANT },
        { ENTRY(bit_stride),                    AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
        { ENTRY(upper_bound),                   AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
        { ENTRY(abstract_origin),               AC_REFERENCE },
        { ENTRY(accessibility),                 AC_CONSTANT },
        { ENTRY(address_class),                 AC_CONSTANT },
        { ENTRY(artificial),                    AC_FLAG },
        { ENTRY(base_types),                    AC_REFERENCE },
        { ENTRY(calling_convention),    AC_CONSTANT },
        { ENTRY(count),                                 AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
        { ENTRY(data_member_location),  AC_BLOCK | AC_CONSTANT | AC_LOCLIST },
        { ENTRY(decl_column),                   AC_CONSTANT },
        { ENTRY(decl_file),                             AC_CONSTANT },
        { ENTRY(decl_line),                             AC_CONSTANT },
        { ENTRY(declaration),                   AC_FLAG },
        { ENTRY(discr_list),                    AC_BLOCK },
        { ENTRY(encoding),                              AC_CONSTANT },
        { ENTRY(external),                              AC_FLAG },
        { ENTRY(frame_base),                    AC_BLOCK | AC_LOCLIST },
        { ENTRY(friend),                                AC_REFERENCE },
        { ENTRY(identifier_case),               AC_CONSTANT },
        { ENTRY(macro_info),                    AC_MACPTR },
        { ENTRY(namelist_item),                 AC_BLOCK | AC_REFERENCE },
        { ENTRY(priority),                              AC_REFERENCE },
        { ENTRY(segment),                               AC_BLOCK | AC_LOCLIST },
        { ENTRY(specification),                 AC_REFERENCE },
        { ENTRY(static_link),                   AC_BLOCK | AC_LOCLIST },
        { ENTRY(type),                                  AC_REFERENCE },
        { ENTRY(use_location),                  AC_BLOCK | AC_LOCLIST },
        { ENTRY(variable_parameter),    AC_FLAG },
        { ENTRY(virtuality),                    AC_CONSTANT },
        { ENTRY(vtable_elem_location),  AC_BLOCK | AC_LOCLIST },
        { ENTRY(allocated),                             AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
        { ENTRY(associated),                    AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
        { ENTRY(data_location),                 AC_BLOCK },
        { ENTRY(byte_stride),                   AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
        { ENTRY(entry_pc),                              AC_ADDRESS },
        { ENTRY(use_UTF8),                              AC_FLAG },
        { ENTRY(extension),                             AC_REFERENCE },
        { ENTRY(ranges),                                AC_RANGELIST },
        { ENTRY(trampoline),                    AC_ADDRESS | AC_FLAG | AC_REFERENCE
                                                                                | AC_STRING },
        { ENTRY(call_column),                   AC_CONSTANT },
        { ENTRY(call_file),                             AC_CONSTANT },
        { ENTRY(call_line),                             AC_CONSTANT },
        { ENTRY(description),                   AC_STRING },
        { ENTRY(binary_scale),                  AC_CONSTANT },
        { ENTRY(decimal_scale),                 AC_CONSTANT },
        { ENTRY(small),                                 AC_REFERENCE },
        { ENTRY(decimal_sign),                  AC_CONSTANT },
        { ENTRY(digit_count),                   AC_CONSTANT },
        { ENTRY(picture_string),                AC_STRING },
        { ENTRY(mutable),                               AC_FLAG },
        { ENTRY(threads_scaled),                AC_FLAG },
        { ENTRY(explicit),                              AC_FLAG },
        { ENTRY(object_pointer),                AC_REFERENCE },
        { ENTRY(endianity),                             AC_CONSTANT },
        { ENTRY(elemental),                             AC_FLAG },
        { ENTRY(pure),                                  AC_FLAG },
        { ENTRY(recursive),                             AC_FLAG },
        { ENTRY(signature),                             AC_REFERENCE },
        { ENTRY(main_subprogram),               AC_FLAG },
        { ENTRY(data_bit_offset),               AC_CONSTANT },
        { ENTRY(const_expr),                    AC_FLAG },
        { ENTRY(enum_class),                    AC_FLAG },
        { ENTRY(linkage_name),                  AC_STRING },
        { ENTRY(string_length_bit_size),
                                                                        AC_CONSTANT },
        { ENTRY(string_length_byte_size),
                                                                        AC_CONSTANT },
        { ENTRY(rank),                                  AC_CONSTANT | AC_BLOCK },
        { ENTRY(str_offsets_base),              AC_STROFFSETSPTR },
        { ENTRY(addr_base),                             AC_ADDRPTR },
        { ENTRY(rnglists_base),                 AC_RANGELISTPTR },
        { ENTRY(dwo_name),                              AC_STRING },
        { ENTRY(reference),                             AC_FLAG },
        { ENTRY(rvalue_reference),              AC_FLAG },
        { ENTRY(macros),                                AC_MACPTR },
        { ENTRY(call_all_calls),                AC_FLAG },
        { ENTRY(call_all_source_calls), AC_FLAG },
        { ENTRY(call_all_tail_calls),   AC_FLAG },
        { ENTRY(call_return_pc),                AC_ADDRESS },
        { ENTRY(call_value),                    AC_BLOCK },
        { ENTRY(call_origin),                   AC_BLOCK },
        { ENTRY(call_parameter),                AC_REFERENCE },
        { ENTRY(call_pc),                               AC_ADDRESS },
        { ENTRY(call_tail_call),                AC_FLAG },
        { ENTRY(call_target),                   AC_BLOCK },
        { ENTRY(call_target_clobbered), AC_BLOCK },
        { ENTRY(call_data_location),    AC_BLOCK },
        { ENTRY(call_data_value),               AC_BLOCK },
        { ENTRY(noreturn),                              AC_FLAG },
        { ENTRY(alignment),                             AC_CONSTANT },
        { ENTRY(export_symbols),                AC_FLAG },
        { ENTRY(deleted),                               AC_FLAG },
        { ENTRY(defaulted),                             AC_CONSTANT },
        { ENTRY(loclists_base),                 AC_LOCLISTPTR },
        { ENTRY(call_site_value),               AC_BLOCK },
        { ENTRY(call_site_data_value),  AC_BLOCK },
        { ENTRY(call_site_target),              AC_BLOCK },
        { ENTRY(call_site_target_clobbered),
                                                                        AC_BLOCK },
        { ENTRY(tail_call),                             AC_FLAG },
        { ENTRY(all_tail_call_sites),   AC_FLAG },
        { ENTRY(all_call_sites),                AC_FLAG },
        { ENTRY(all_source_call_sites), AC_FLAG },

        {}
};

static const uint32 kAttributeNameInfoCount = DW_AT_loclists_base + 9;
static attribute_name_info_entry sAttributeNameInfos[kAttributeNameInfoCount];


#undef ENTRY
#define ENTRY(name)     "DW_FORM_" #name, DW_FORM_##name

static const attribute_info_entry kAttributeFormInfos[] = {
        { ENTRY(addr),                  AC_ADDRESS },
        { ENTRY(block2),                AC_BLOCK },
        { ENTRY(block4),                AC_BLOCK },
        { ENTRY(data2),                 AC_CONSTANT },
        { ENTRY(data4),                 AC_CONSTANT | AC_LINEPTR | AC_LOCLIST
                                                                | AC_MACPTR | AC_RANGELIST },
        { ENTRY(data8),                 AC_CONSTANT | AC_LINEPTR | AC_LOCLIST
                                                                | AC_MACPTR | AC_RANGELIST },
        { ENTRY(string),                AC_STRING },
        { ENTRY(block),                 AC_BLOCK },
        { ENTRY(block1),                AC_BLOCK },
        { ENTRY(data1),                 AC_CONSTANT },
        { ENTRY(flag),                  AC_FLAG },
        { ENTRY(sdata),                 AC_CONSTANT },
        { ENTRY(strp),                  AC_STRING },
        { ENTRY(udata),                 AC_CONSTANT },
        { ENTRY(ref_addr),              AC_REFERENCE },
        { ENTRY(ref1),                  AC_REFERENCE },
        { ENTRY(ref2),                  AC_REFERENCE },
        { ENTRY(ref4),                  AC_REFERENCE },
        { ENTRY(ref8),                  AC_REFERENCE },
        { ENTRY(ref_udata),             AC_REFERENCE },
        { ENTRY(indirect),              AC_REFERENCE },
        { ENTRY(sec_offset),    AC_ADDRPTR | AC_LINEPTR
                                                                | AC_LOCLIST | AC_LOCLISTPTR
                                                                | AC_MACPTR
                                                                | AC_RANGELIST | AC_RANGELISTPTR
                                                                | AC_STROFFSETSPTR  },
        { ENTRY(exprloc),               AC_BLOCK },
        { ENTRY(flag_present),  AC_FLAG },
        { ENTRY(strx),                  AC_STRING },
        { ENTRY(addrx),                 AC_ADDRESS },
        { ENTRY(ref_sup4),              AC_REFERENCE },
        { ENTRY(strp_sup),              AC_STRING },
        { ENTRY(data16),                AC_CONSTANT },
        { ENTRY(line_strp),             AC_STRING },
        { ENTRY(ref_sig8),              AC_REFERENCE },
        { ENTRY(implicit_const),
                                                        AC_CONSTANT },
        { ENTRY(loclistx),              AC_LOCLIST },
        { ENTRY(rnglistx),              AC_RANGELIST },
        { ENTRY(ref_sup8),              AC_REFERENCE },
        { ENTRY(strx1),                 AC_STRING },
        { ENTRY(strx2),                 AC_STRING },
        { ENTRY(strx3),                 AC_STRING },
        { ENTRY(strx4),                 AC_STRING },
        { ENTRY(addrx1),                AC_ADDRESS },
        { ENTRY(addrx2),                AC_ADDRESS },
        { ENTRY(addrx3),                AC_ADDRESS },
        { ENTRY(addrx4),                AC_ADDRESS },
        {}
};

static const uint32 kAttributeFormInfoCount = DW_FORM_addrx4 + 1;
static attribute_info_entry sAttributeFormInfos[kAttributeFormInfoCount];

static struct InitAttributeInfos {
        InitAttributeInfos()
        {
                for (uint32 i = 0; kAttributeNameInfos[i].name != NULL; i++) {
                        const attribute_name_info_entry& entry = kAttributeNameInfos[i];
                        if (entry.value <= DW_AT_loclists_base)
                                sAttributeNameInfos[entry.value] = entry;
                        else {
                                sAttributeNameInfos[DW_AT_loclists_base + 1
                                        + (entry.value - DW_AT_call_site_value)] = entry;
                        }
                }

                for (uint32 i = 0; kAttributeFormInfos[i].name != NULL; i++) {
                        const attribute_info_entry& entry = kAttributeFormInfos[i];
                        sAttributeFormInfos[entry.value] = entry;
                }
        }
} sInitAttributeInfos;


uint16
get_attribute_name_classes(uint32 name)
{
        if (name <= DW_AT_loclists_base)
                return sAttributeNameInfos[name].classes;
        else if (name >= DW_AT_call_site_value
                && name <= DW_AT_all_source_call_sites) {
                return sAttributeNameInfos[DW_AT_loclists_base + 1
                        + (name - DW_AT_call_site_value)].classes;
        }

        return 0;
}


uint16
get_attribute_form_classes(uint32 form)
{
        return form < kAttributeFormInfoCount
                ? sAttributeFormInfos[form].classes : 0;
}


uint8
get_attribute_class(uint32 name, uint32 form)
{
        uint16 classes = get_attribute_name_classes(name)
                & get_attribute_form_classes(form);

        int clazz = 0;
        while (classes != 0) {
                classes >>= 1;
                clazz++;
        }

        return clazz;
}


const char*
get_attribute_name_name(uint32 name)
{
        if (name <= DW_AT_loclists_base)
                return sAttributeNameInfos[name].name;
        else if (name >= DW_AT_call_site_value
                && name <= DW_AT_all_source_call_sites) {
                return sAttributeNameInfos[DW_AT_loclists_base + 1 +
                                (name - DW_AT_call_site_value)].name;
        }

        return NULL;
}


const char*
get_attribute_form_name(uint32 form)
{
        return form < kAttributeFormInfoCount
                ? sAttributeFormInfos[form].name : NULL;
}


DebugInfoEntrySetter
get_attribute_name_setter(uint32 name)
{
        return (name < kAttributeNameInfoCount)
                ? sAttributeNameInfos[name].setter : NULL;
}