root/src/kits/debugger/dwarf/AbbreviationTable.cpp
/*
 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */

#include "AbbreviationTable.h"

#include <stdio.h>

#include <new>


AbbreviationTable::AbbreviationTable(off_t offset)
        :
        fOffset(offset),
        fData(NULL),
        fSize(0)
{
}


AbbreviationTable::~AbbreviationTable()
{
        AbbreviationTableEntry* entry = fEntryTable.Clear(true);
        while (entry != NULL) {
                AbbreviationTableEntry* next = entry->next;
                delete entry;
                entry = next;
        }
}


status_t
AbbreviationTable::Init(const void* section, off_t sectionSize)
{
        if (fOffset < 0 || fOffset >= sectionSize)
                return B_BAD_DATA;

        fData = (uint8*)section + fOffset;
        fSize = sectionSize - fOffset;
                // That's only the maximum size. Will be adjusted at the end.

        status_t error = fEntryTable.Init();
        if (error != B_OK)
                return error;

        DataReader abbrevReader(fData, fSize, 4, false);
                // address size and endianness don't matter here

        while (true) {
                bool nullEntry;
                status_t error = _ParseAbbreviationEntry(abbrevReader, nullEntry);
                if (error != B_OK)
                        return error;

                if (nullEntry)
                        break;
        }

        fSize -= abbrevReader.BytesRemaining();

        return B_OK;
}


bool
AbbreviationTable::GetAbbreviationEntry(uint32 code, AbbreviationEntry& entry)
{
        AbbreviationTableEntry* tableEntry = fEntryTable.Lookup(code);
        if (tableEntry == NULL)
                return false;

        entry.SetTo(code, fData + tableEntry->offset, tableEntry->size);
        return true;
}


status_t
AbbreviationTable::_ParseAbbreviationEntry(DataReader& abbrevReader,
        bool& _nullEntry)
{
        uint32 code = abbrevReader.ReadUnsignedLEB128(0);
        if (code == 0) {
                if (abbrevReader.HasOverflow()) {
                        fprintf(stderr, "Invalid abbreviation table 1!\n");
                        return B_BAD_DATA;
                }
                _nullEntry = true;
                return B_OK;
        }

        off_t remaining = abbrevReader.BytesRemaining();

/*      uint32 tag =*/ abbrevReader.ReadUnsignedLEB128(0);
/*      uint8 hasChildren =*/ abbrevReader.Read<uint8>(DW_CHILDREN_no);

//      printf("entry: %" B_PRIu32 ", tag: %" B_PRIu32 ", children: %d\n", code, tag,
//              hasChildren);

        // parse attribute specifications
        while (true) {
                uint32 attributeName = abbrevReader.ReadUnsignedLEB128(0);
                uint32 attributeForm = abbrevReader.ReadUnsignedLEB128(0);
                if (abbrevReader.HasOverflow()) {
                        fprintf(stderr, "Invalid abbreviation table 2!\n");
                        return B_BAD_DATA;
                }

                if (attributeName == 0 && attributeForm == 0)
                        break;

                if (attributeForm == DW_FORM_implicit_const)
                        abbrevReader.ReadSignedLEB128(0);

//              printf("  attr: name: %" B_PRIu32 ", form: %" B_PRIu32 "\n", attributeName,
//                      attributeForm);
        }

        // create the entry
        if (fEntryTable.Lookup(code) == NULL) {
                AbbreviationTableEntry* entry = new(std::nothrow)
                        AbbreviationTableEntry(code, fSize - remaining,
                                remaining - abbrevReader.BytesRemaining());
                if (entry == NULL)
                        return B_NO_MEMORY;

                fEntryTable.Insert(entry);
        } else {
                fprintf(stderr, "Duplicate abbreviation table entry %" B_PRIu32 "!\n",
                        code);
        }

        _nullEntry = false;
        return B_OK;
}