diff options
Diffstat (limited to 'dwarfdump/checkutil.c')
-rw-r--r-- | dwarfdump/checkutil.c | 565 |
1 files changed, 565 insertions, 0 deletions
diff --git a/dwarfdump/checkutil.c b/dwarfdump/checkutil.c new file mode 100644 index 0000000..6ba756c --- /dev/null +++ b/dwarfdump/checkutil.c @@ -0,0 +1,565 @@ +/* + Copyright (C) 2011 SN Systems Ltd. All Rights Reserved. + Portions Copyright (C) 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street - Fifth Floor, Boston MA 02110-1301, USA. + +*/ +/* + + These simple list-processing functions are in support + of checking DWARF for compiler-errors of various sorts. + + +*/ + +#include "globals.h" +#include <assert.h> + +/* Private function */ +static void DumpFullBucketGroup(Bucket_Group *pBucketGroup); +static int FindDataIndexInBucket(Bucket_Group *pBucketGroup, + Bucket_Data *pBucketData); +static void PrintBucketData(Bucket_Group *pBucketGroup, + Bucket_Data *pBucketData); +static void ProcessBucketGroup(Bucket_Group *pBucketGroup, + void (*pFunction)(Bucket_Group *pBucketGroup,Bucket_Data *pBucketData)); + +Bucket_Group * +AllocateBucketGroup(int kind) +{ + Bucket_Group *pBucketGroup = (Bucket_Group *)calloc(1,sizeof(Bucket_Group)); + pBucketGroup->kind = kind; + return pBucketGroup; +} + +void +ReleaseBucketGroup(Bucket_Group *pBucketGroup) +{ + Bucket *pBucket = 0; + Bucket *pNext = 0; + + assert(pBucketGroup); + for (pBucket = pBucketGroup->pHead; pBucket; /*pBucket = pBucket->pNext*/) { + pNext = pBucket->pNext; + free(pBucket); + pBucket = pNext; + } + pBucketGroup->pHead = NULL; + pBucketGroup->pTail = NULL; + free(pBucketGroup); +} + +void +ResetBucketGroup(Bucket_Group *pBucketGroup) +{ + Bucket *pBucket = 0; + + assert(pBucketGroup); + for (pBucket = pBucketGroup->pHead; pBucket; pBucket = pBucket->pNext) { + pBucket->nEntries = 0; + } + ResetSentinelBucketGroup(pBucketGroup); +} + +/* Reset sentinels in a Bucket Group. */ +void +ResetSentinelBucketGroup(Bucket_Group *pBucketGroup) +{ + /* Sanity checks */ + assert(pBucketGroup); + pBucketGroup->pFirst = NULL; + pBucketGroup->pLast = NULL; +} + +void PrintBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Bool bFull) +{ + assert(pBucketGroup); + if (bFull) { + DumpFullBucketGroup(pBucketGroup); + } else { + if (pBucketGroup->pFirst && pBucketGroup->pLast) { + printf("\nBegin Traversing, First = 0x%08" DW_PR_DUx + ", Last = 0x%08" DW_PR_DUx "\n", + pBucketGroup->pFirst->key,pBucketGroup->pLast->key); + ProcessBucketGroup(pBucketGroup,PrintBucketData); + } + } +} + +static void +PrintBucketData(Bucket_Group *pBucketGroup,Bucket_Data *pBucketData) +{ + int nCount = 0; + assert(pBucketGroup); + assert(pBucketData); + + nCount = FindDataIndexInBucket(pBucketGroup,pBucketData); + printf("[%06d] Key = 0x%08" DW_PR_DUx ", Base = 0x%08" DW_PR_DUx + ", Low = 0x%08" DW_PR_DUx ", High = 0x%08" DW_PR_DUx + ", Flag = %d, Name = '%s'\n", + ++nCount, + pBucketData->key, + pBucketData->base, + pBucketData->low, + pBucketData->high, + pBucketData->bFlag, + pBucketData->name); +} + +static void +DumpFullBucketGroup(Bucket_Group *pBucketGroup) +{ + int nBucketNo = 1; + int nIndex = 0; + int nCount = 0; + Bucket *pBucket = 0; + Bucket_Data *pBucketData = 0; + + assert(pBucketGroup); + for (pBucket = pBucketGroup->pHead; pBucket && pBucket->nEntries; + pBucket = pBucket->pNext) { + + printf("\nLowPC & HighPC records for bucket %d, at 0x%08lx\n", + nBucketNo++,(unsigned long)pBucket); + for (nIndex = 0; nIndex < pBucket->nEntries; ++nIndex) { + pBucketData = &pBucket->Entries[nIndex]; + printf("[%06d] Key = 0x%08" DW_PR_DUx ", Base = 0x%08" DW_PR_DUx + ", Low = 0x%08" DW_PR_DUx ", High = 0x%08" DW_PR_DUx + ", Flag = %d, Name = '%s'\n", + ++nCount, + pBucketData->key, + pBucketData->base, + pBucketData->low, + pBucketData->high, + pBucketData->bFlag, + pBucketData->name); + } + } +} + +/* Insert entry into Bucket Group. + We make no check for duplicate information. */ +void +AddEntryIntoBucketGroup(Bucket_Group *pBucketGroup, + Dwarf_Addr key,Dwarf_Addr base, + Dwarf_Addr low,Dwarf_Addr high, + const char *name, + Dwarf_Bool bFlag) +{ + Bucket *pBucket = 0; + Bucket_Data data; + + data.bFlag = bFlag; + data.name = name; + data.key = key; + data.base = base; + data.low = low; + data.high = high; + + assert(pBucketGroup); + if (!pBucketGroup->pHead) { + /* Allocate first bucket */ + pBucket = (Bucket *)calloc(1,sizeof(Bucket)); + pBucketGroup->pHead = pBucket; + pBucketGroup->pTail = pBucket; + pBucket->nEntries = 1; + pBucket->Entries[0] = data; + return; + } + + pBucket = pBucketGroup->pTail; + + /* Check if we have a previous allocated set of + buckets (have been cleared */ + if (pBucket->nEntries) { + if (pBucket->nEntries < BUCKET_SIZE) { + pBucket->Entries[pBucket->nEntries++] = data; + } else { + /* Allocate new bucket */ + pBucket = (Bucket *)calloc(1,sizeof(Bucket)); + pBucketGroup->pTail->pNext = pBucket; + pBucketGroup->pTail = pBucket; + pBucket->nEntries = 1; + pBucket->Entries[0] = data; + } + } else { + /* We have an allocated bucket with zero entries; search for the + first available bucket to be used as the current + insertion point */ + for (pBucket = pBucketGroup->pHead; pBucket; + pBucket = pBucket->pNext) { + + if (pBucket->nEntries < BUCKET_SIZE) { + pBucket->Entries[pBucket->nEntries++] = data; + break; + } + } + } +} + +/* For Groups where entries are individually deleted, this does + that work. */ +Dwarf_Bool +DeleteKeyInBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Addr key) +{ + int nIndex = 0; + Bucket *pBucket = 0; + Bucket_Data *pBucketData = 0; + + /* Sanity checks */ + assert(pBucketGroup); + + /* For now do a linear search */ + for (pBucket = pBucketGroup->pHead; pBucket && pBucket->nEntries; + pBucket = pBucket->pNext) { + + for (nIndex = 0; nIndex < pBucket->nEntries; ++nIndex) { + pBucketData = &pBucket->Entries[nIndex]; + if (pBucketData->key == key) { + Bucket_Data data = {FALSE,NULL,0,0,0,0}; + int nStart; + for (nStart = nIndex + 1; nStart < pBucket->nEntries; + ++nStart) { + + pBucket->Entries[nIndex] = pBucket->Entries[nStart]; + ++nIndex; + } + pBucket->Entries[nIndex] = data; + --pBucket->nEntries; + return TRUE; + } + } + } + return FALSE; +} + +/* Search to see if the address is in the range between + low and high addresses in some Bucked Data record. + This matches == if high is exact match (which usually means + one-past-true-high). */ +Dwarf_Bool +FindAddressInBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Addr address) +{ + int nIndex = 0; + Bucket *pBucket = 0; + Bucket_Data *pBucketData = 0; + + assert(pBucketGroup); + /* For now do a linear search */ + for (pBucket = pBucketGroup->pHead; pBucket && pBucket->nEntries; + pBucket = pBucket->pNext) { + + for (nIndex = 0; nIndex < pBucket->nEntries; ++nIndex) { + pBucketData = &pBucket->Entries[nIndex]; + if (address >= pBucketData->low && + address <= pBucketData->high) { + return TRUE; + } + } + } + return FALSE; +} + +/* Search an entry (Bucket Data) in the Bucket Set */ +Bucket_Data *FindDataInBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Addr key) +{ + int mid = 0; + int low = 0; + int high = 0; + Bucket *pBucket = 0; + Bucket_Data *pBucketData = 0; + + assert(pBucketGroup); + + for (pBucket = pBucketGroup->pHead; pBucket; pBucket = pBucket->pNext) { + /* Get lower and upper references */ + if (pBucket->nEntries) { + low = 0; + high = pBucket->nEntries; + while (low < high) { + mid = low + (high - low) / 2; + if (pBucket->Entries[mid].key < key) { + low = mid + 1; + } else { + high = mid; + } + } + if ((low < pBucket->nEntries) && + (pBucket->Entries[low].key == key)) { + + pBucketData = &pBucket->Entries[low]; + /* Update sentinels to allow traversing the table */ + if (!pBucketGroup->pFirst) { + pBucketGroup->pFirst = pBucketData; + } + pBucketGroup->pLast = pBucketData; + return pBucketData; + } + } + } + return (Bucket_Data *)NULL; +} + +/* Find the Bucket that contains a given Bucket Data + and return its local index. Else return -1. */ +static int +FindDataIndexInBucket(Bucket_Group *pBucketGroup,Bucket_Data *pBucketData) +{ + Bucket *pBucket = 0; + Bucket_Data *pLower = 0; + Bucket_Data *pUpper = 0; + + /* Sanity checks */ + assert(pBucketGroup); + assert(pBucketData); + + /* Use sentinels if any. */ + if (pBucketGroup->pFirst && pBucketGroup->pLast && + pBucketData >= pBucketGroup->pFirst && + pBucketData <= pBucketGroup->pLast) { + + /* Find bucket that contains the first sentinel */ + for (pBucket = pBucketGroup->pHead; pBucket && pBucket->nEntries; + pBucket = pBucket->pNext) { + + pLower = &pBucket->Entries[0]; + pUpper = &pBucket->Entries[pBucket->nEntries - 1]; + + /* Check if the first sentinel is in this bucket. */ + if (pBucketGroup->pFirst >= pLower && + pBucketGroup->pFirst <= pUpper) { + /* We have found the bucket, return the index. */ + return pBucketData - pBucketGroup->pFirst; + } + } + } else { + /* Find bucket that contains the entry */ + for (pBucket = pBucketGroup->pHead; pBucket && pBucket->nEntries; + pBucket = pBucket->pNext) { + + pLower = &pBucket->Entries[0]; + pUpper = &pBucket->Entries[pBucket->nEntries - 1]; + + /* Check if the first sentinel is in this bucket */ + if (pBucketData >= pLower && pBucketData <= pUpper) { + /* We have found the bucket, return the index */ + return pBucketData - pLower; + } + } + } + /* Invalid data; just return index indicating not-found */ + return -1; +} + +/* Search an entry (Bucket Data) in the Bucket Group. + The key is an offset, a DIE offset + within Visited info. */ +Bucket_Data *FindKeyInBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Addr key) +{ + int nIndex = 0; + Bucket *pBucket = 0; + Bucket_Data *pBucketData = 0; + + /* Sanity checks */ + assert(pBucketGroup); + + /* For now do a linear search */ + for (pBucket = pBucketGroup->pHead; pBucket && pBucket->nEntries; + pBucket = pBucket->pNext) { + for (nIndex = 0; nIndex < pBucket->nEntries; ++nIndex) { + pBucketData = &pBucket->Entries[nIndex]; + if (pBucketData->key == key) { + return pBucketData; + } + } + } + return (Bucket_Data *)NULL; +} + +/* Search an entry (Bucket Data) in the Bucket Set by name. + Used to find link-once section names. */ +Bucket_Data * +FindNameInBucketGroup(Bucket_Group *pBucketGroup,char *name) +{ + int nIndex = 0; + Bucket *pBucket = 0; + Bucket_Data *pBucketData = 0; + + assert(pBucketGroup); + /* For now do a linear search. */ + for (pBucket = pBucketGroup->pHead; pBucket && pBucket->nEntries; + pBucket = pBucket->pNext) { + for (nIndex = 0; nIndex < pBucket->nEntries; ++nIndex) { + pBucketData = &pBucket->Entries[nIndex]; + if (!strcmp(pBucketData->name,name)) { + return pBucketData; + } + } + } + return (Bucket_Data *)NULL; +} + +/* Check if an address valid or not. That is, + check if it is in the lower -> upper range of a bucket. + It checks <= and >= so the lower end + and one-past on the upper end matches. +*/ +Dwarf_Bool +IsValidInBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Addr address) +{ + Bucket *pBucket = 0; + Bucket_Data *pBucketData = 0; + int nIndex = 0; + + assert(pBucketGroup); + /* Check the address is within the allowed limits */ + if (address >= pBucketGroup->lower && address <= pBucketGroup->upper) { + for (pBucket = pBucketGroup->pHead; pBucket && pBucket->nEntries; + pBucket = pBucket->pNext) { + + for (nIndex = 0; nIndex < pBucket->nEntries; ++nIndex) { + pBucketData = &pBucket->Entries[nIndex]; + if (address >= pBucketData->low && + address <= pBucketData->high) { + return TRUE; + } + } + } + } + return FALSE; +} + +/* Reset limits for values in the Bucket Set */ +void +ResetLimitsBucketSet(Bucket_Group *pBucketGroup) +{ + assert(pBucketGroup); + pBucketGroup->lower = 0; + pBucketGroup->upper = 0; +} + +/* Limits are set only for ranges, so only in pRangesInfo. */ +void +SetLimitsBucketGroup(Bucket_Group *pBucketGroup, + Dwarf_Addr lower,Dwarf_Addr upper) +{ + assert(pBucketGroup); + if (lower < upper) { + pBucketGroup->lower = lower; + pBucketGroup->upper = upper; + } +} + +/* Traverse Bucket Set and execute a supplied function */ +static void +ProcessBucketGroup(Bucket_Group *pBucketGroup, + void (*pFunction)(Bucket_Group *pBucketGroup,Bucket_Data *pBucketData)) +{ + int nIndex = 0; + int nStart = 0; + Bucket *pBucket = 0; + Bucket_Data *pBucketData = 0; + Bucket_Data *pLower = 0; + Bucket_Data *pUpper = 0; + Dwarf_Bool bFound = FALSE; + + /* Sanity checks */ + assert(pBucketGroup); + + /* No sentinels present; do nothing */ + if (!pBucketGroup->pFirst || !pBucketGroup->pLast) { + return; + } + + /* Find bucket that contains the first sentinel */ + for (pBucket = pBucketGroup->pHead; pBucket && pBucket->nEntries; + pBucket = pBucket->pNext) { + + pLower = &pBucket->Entries[0]; + pUpper = &pBucket->Entries[pBucket->nEntries - 1]; + + /* Check if the first sentinel is in this bucket */ + if (pBucketGroup->pFirst >= pLower && pBucketGroup->pFirst <= pUpper) { + /* Low sentinel is in this bucket */ + bFound = TRUE; + break; + } + } + + /* Invalid sentinel; do nothing */ + if (!bFound) { + return; + } + + /* Calculate index for first sentinel */ + nStart = pBucketGroup->pFirst - pLower; + + /* Start traversing from found bucket */ + for (; pBucket && pBucket->nEntries; pBucket = pBucket->pNext) { + for (nIndex = nStart; nIndex < pBucket->nEntries; ++nIndex) { + pBucketData = &pBucket->Entries[nIndex]; + if (pBucketData > pBucketGroup->pLast) { + return; + } + /* Call the user supplied function */ + if (pFunction) { + pFunction(pBucketGroup,pBucketData); + } + } + /* For next bucket start with first entry */ + nStart = 0; + } +} + +/* Check if a given (lopc,hipc) are valid for a linkonce. + We pass in the linkonce (instead of + referencing the global pLinkonceInfo) as that means + searches for pLinkonceInfo find all the uses, + making understanding of the code a tiny bit easier. + The section name created is supposed to be the appropriate + linkonce section name. +*/ +Dwarf_Bool IsValidInLinkonce(Bucket_Group *pLo, + const char *name,Dwarf_Addr lopc,Dwarf_Addr hipc) +{ +#define SECTION_NAME_LEN 2048 /* Guessing a sensible length */ + static char section_name[SECTION_NAME_LEN]; + Bucket_Data *pBucketData = 0; + /* Since text is quite uniformly just this name, no need to get it + from elsewhere, though it will not work for non-elf. */ + const char *lo_text = ".text"; + + /* Build the name that represents the linkonce section (.text). + This is not defined in DWARF so not correct for all + compilers. */ + snprintf(section_name,sizeof(section_name),"%s%s",lo_text,name); + + pBucketData = FindNameInBucketGroup(pLo,section_name); + if (pBucketData) { + if (lopc >= pBucketData->low && lopc <= pBucketData->high) { + if (hipc >= pBucketData->low && hipc <= pBucketData->high) { + return TRUE; + } + } + } + return FALSE; +} + |