|
|
|
@@ -442,6 +442,45 @@ private:
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// #pragma mark - FDELookupInfo
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct DwarfFile::FDELookupInfo {
|
|
|
|
|
public:
|
|
|
|
|
FDELookupInfo(target_addr_t start, target_addr_t end,
|
|
|
|
|
uint64 fdeOffset, uint64 cieOffset, bool ehFrame)
|
|
|
|
|
:
|
|
|
|
|
start(start),
|
|
|
|
|
end(end),
|
|
|
|
|
fdeOffset(fdeOffset),
|
|
|
|
|
cieOffset(cieOffset),
|
|
|
|
|
ehFrame(ehFrame)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int CompareFDEInfos(const FDELookupInfo* a, const FDELookupInfo* b)
|
|
|
|
|
{
|
|
|
|
|
if (a->start < b->start)
|
|
|
|
|
return -1;
|
|
|
|
|
else if (a->start > b->start)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool ContainsAddress(target_addr_t address) const
|
|
|
|
|
{
|
|
|
|
|
return address >= start && address < end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
target_addr_t start;
|
|
|
|
|
target_addr_t end;
|
|
|
|
|
uint64 fdeOffset;
|
|
|
|
|
uint64 cieOffset;
|
|
|
|
|
bool ehFrame;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// #pragma mark - DwarfFile
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -462,8 +501,12 @@ DwarfFile::DwarfFile()
|
|
|
|
|
fDebugPublicTypesSection(NULL),
|
|
|
|
|
fDebugTypesSection(NULL),
|
|
|
|
|
fCompilationUnits(20, true),
|
|
|
|
|
fTypeUnits(),
|
|
|
|
|
fDebugFrameInfos(100, true),
|
|
|
|
|
fEHFrameInfos(100, true),
|
|
|
|
|
fTypesSectionRequired(false),
|
|
|
|
|
fFinished(false),
|
|
|
|
|
fItaniumEHFrameFormat(false),
|
|
|
|
|
fFinishError(B_OK)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
@@ -528,7 +571,7 @@ DwarfFile::StartLoading(const char* fileName, BString& _requiredExternalFile)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
|
DwarfFile::Load(const BString& externalInfoFilePath)
|
|
|
|
|
DwarfFile::Load(uint8 addressSize, const BString& externalInfoFilePath)
|
|
|
|
|
{
|
|
|
|
|
status_t error = B_OK;
|
|
|
|
|
if (fDebugInfoSection == NULL) {
|
|
|
|
@@ -547,11 +590,27 @@ DwarfFile::Load(const BString& externalInfoFilePath)
|
|
|
|
|
fDebugRangesSection = debugInfoFile->GetSection(".debug_ranges");
|
|
|
|
|
fDebugLineSection = debugInfoFile->GetSection(".debug_line");
|
|
|
|
|
fDebugFrameSection = debugInfoFile->GetSection(".debug_frame");
|
|
|
|
|
|
|
|
|
|
if (fDebugFrameSection != NULL) {
|
|
|
|
|
error = _ParseFrameSection(fDebugFrameSection, addressSize, false,
|
|
|
|
|
fDebugFrameInfos);
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// .eh_frame doesn't appear to get copied into separate debug
|
|
|
|
|
// info files properly, therefore always use it off the main
|
|
|
|
|
// executable image
|
|
|
|
|
if (fEHFrameSection == NULL)
|
|
|
|
|
fEHFrameSection = fElfFile->GetSection(".eh_frame");
|
|
|
|
|
|
|
|
|
|
if (fEHFrameSection != NULL) {
|
|
|
|
|
error = _ParseFrameSection(fEHFrameSection, addressSize, true,
|
|
|
|
|
fEHFrameInfos);
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fDebugLocationSection = debugInfoFile->GetSection(".debug_loc");
|
|
|
|
|
fDebugPublicTypesSection = debugInfoFile->GetSection(".debug_pubtypes");
|
|
|
|
|
|
|
|
|
@@ -699,22 +758,12 @@ DwarfFile::UnwindCallFrame(CompilationUnit* unit, uint8 addressSize,
|
|
|
|
|
const DwarfTargetInterface* inputInterface,
|
|
|
|
|
DwarfTargetInterface* outputInterface, target_addr_t& _framePointer)
|
|
|
|
|
{
|
|
|
|
|
status_t result = B_ENTRY_NOT_FOUND;
|
|
|
|
|
FDELookupInfo* info = _GetContainingFDEInfo(location);
|
|
|
|
|
if (info == NULL)
|
|
|
|
|
return B_ENTRY_NOT_FOUND;
|
|
|
|
|
|
|
|
|
|
// first try to find the FDE in .debug_frame
|
|
|
|
|
if (fDebugFrameSection != NULL) {
|
|
|
|
|
result = _UnwindCallFrame(false, unit, addressSize, subprogramEntry,
|
|
|
|
|
location, inputInterface, outputInterface, _framePointer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if .debug_frame isn't present, or if the FDE wasn't found there,
|
|
|
|
|
// try .eh_frame
|
|
|
|
|
if (result == B_ENTRY_NOT_FOUND && fEHFrameSection != NULL) {
|
|
|
|
|
result = _UnwindCallFrame(true, unit, addressSize, subprogramEntry,
|
|
|
|
|
location, inputInterface, outputInterface, _framePointer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
return _UnwindCallFrame(unit, addressSize, subprogramEntry, location, info,
|
|
|
|
|
inputInterface, outputInterface, _framePointer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1080,6 +1129,116 @@ DwarfFile::_ParseTypesSection()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
|
DwarfFile::_ParseFrameSection(ElfSection* section, uint8 addressSize,
|
|
|
|
|
bool ehFrame, FDEInfoList& infos)
|
|
|
|
|
{
|
|
|
|
|
if (ehFrame) {
|
|
|
|
|
fItaniumEHFrameFormat = section->IsWritable();
|
|
|
|
|
// Crude heuristic for recognizing GCC 4 (Itanium ABI) style
|
|
|
|
|
// .eh_frame sections. The ones generated by GCC 2 are writable,
|
|
|
|
|
// the ones generated by GCC 4 aren't.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DataReader dataReader((uint8*)section->Data(),
|
|
|
|
|
section->Size(), addressSize);
|
|
|
|
|
|
|
|
|
|
while (dataReader.BytesRemaining() > 0) {
|
|
|
|
|
// length
|
|
|
|
|
bool dwarf64;
|
|
|
|
|
off_t entryOffset = dataReader.Offset();
|
|
|
|
|
uint64 length = dataReader.ReadInitialLength(dwarf64);
|
|
|
|
|
|
|
|
|
|
TRACE_CFI("DwarfFile::_ParseFrameSection(): offset: %" B_PRIdOFF
|
|
|
|
|
", length: %" B_PRId64 "\n", entryOffset, length);
|
|
|
|
|
|
|
|
|
|
if (length > (uint64)dataReader.BytesRemaining())
|
|
|
|
|
return B_BAD_DATA;
|
|
|
|
|
off_t lengthOffset = dataReader.Offset();
|
|
|
|
|
|
|
|
|
|
// CIE ID/CIE pointer
|
|
|
|
|
uint64 cieID = dwarf64
|
|
|
|
|
? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
|
|
|
|
|
|
|
|
|
|
// In .debug_frame ~0 indicates a CIE, in .eh_frame 0 does.
|
|
|
|
|
if (ehFrame
|
|
|
|
|
? cieID == 0
|
|
|
|
|
: (dwarf64
|
|
|
|
|
? cieID == 0xffffffffffffffffULL
|
|
|
|
|
: cieID == 0xffffffff)) {
|
|
|
|
|
// this is a CIE -- skip it
|
|
|
|
|
} else {
|
|
|
|
|
// this is a FDE
|
|
|
|
|
uint64 initialLocationOffset = dataReader.Offset();
|
|
|
|
|
// In .eh_frame the CIE offset is a relative back offset.
|
|
|
|
|
if (ehFrame) {
|
|
|
|
|
if (cieID > (uint64)lengthOffset) {
|
|
|
|
|
TRACE_CFI("Invalid CIE offset: %" B_PRIu64 ", max "
|
|
|
|
|
"possible: %" B_PRIu64 "\n", cieID, lengthOffset);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// convert to a section relative offset
|
|
|
|
|
cieID = lengthOffset - cieID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CfaContext context;
|
|
|
|
|
CIEAugmentation cieAugmentation;
|
|
|
|
|
// when using .eh_frame format, we need to parse the CIE's
|
|
|
|
|
// augmentation up front in order to know how the FDE's addresses
|
|
|
|
|
// will be represented
|
|
|
|
|
DataReader cieReader;
|
|
|
|
|
off_t cieRemaining;
|
|
|
|
|
status_t error = _ParseCIEHeader(section, ehFrame, NULL,
|
|
|
|
|
addressSize, context, cieID, cieAugmentation, cieReader,
|
|
|
|
|
cieRemaining);
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
if (cieReader.HasOverflow())
|
|
|
|
|
return B_BAD_DATA;
|
|
|
|
|
if (cieRemaining < 0)
|
|
|
|
|
return B_BAD_DATA;
|
|
|
|
|
|
|
|
|
|
target_addr_t initialLocation = cieAugmentation.ReadEncodedAddress(
|
|
|
|
|
dataReader, fElfFile, section);
|
|
|
|
|
target_addr_t addressRange = cieAugmentation.ReadEncodedAddress(
|
|
|
|
|
dataReader, fElfFile, section, true);
|
|
|
|
|
|
|
|
|
|
if (dataReader.HasOverflow())
|
|
|
|
|
return B_BAD_DATA;
|
|
|
|
|
|
|
|
|
|
if ((cieAugmentation.FDEAddressType()
|
|
|
|
|
& CFI_ADDRESS_TYPE_PC_RELATIVE) != 0) {
|
|
|
|
|
initialLocation += initialLocationOffset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for unknown reasons, the debug frame sections generated by gcc
|
|
|
|
|
// sometimes contain duplicates at different offsets within the
|
|
|
|
|
// section. In such a case, simply skip the duplicates.
|
|
|
|
|
FDELookupInfo* temp = _GetContainingFDEInfo(initialLocation,
|
|
|
|
|
infos);
|
|
|
|
|
if (temp == NULL) {
|
|
|
|
|
FDELookupInfo* info = new(std::nothrow)FDELookupInfo(
|
|
|
|
|
initialLocation, initialLocation + addressRange - 1,
|
|
|
|
|
entryOffset, cieID, ehFrame);
|
|
|
|
|
if (info == NULL)
|
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
|
|
|
|
|
ObjectDeleter<FDELookupInfo> infoDeleter(info);
|
|
|
|
|
if (!infos.BinaryInsert(info, FDELookupInfo::CompareFDEInfos))
|
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
|
|
|
|
|
infoDeleter.Detach();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dataReader.SeekAbsolute(lengthOffset + length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
|
DwarfFile::_ParseCompilationUnit(CompilationUnit* unit)
|
|
|
|
|
{
|
|
|
|
@@ -1705,305 +1864,230 @@ DwarfFile::_ParseLineInfo(CompilationUnit* unit)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
|
DwarfFile::_UnwindCallFrame(bool usingEHFrameSection, CompilationUnit* unit,
|
|
|
|
|
uint8 addressSize, DIESubprogram* subprogramEntry, target_addr_t location,
|
|
|
|
|
const DwarfTargetInterface* inputInterface,
|
|
|
|
|
DwarfFile::_UnwindCallFrame(CompilationUnit* unit, uint8 addressSize,
|
|
|
|
|
DIESubprogram* subprogramEntry, target_addr_t location,
|
|
|
|
|
const FDELookupInfo* info, const DwarfTargetInterface* inputInterface,
|
|
|
|
|
DwarfTargetInterface* outputInterface, target_addr_t& _framePointer)
|
|
|
|
|
{
|
|
|
|
|
ElfSection* currentFrameSection = (usingEHFrameSection)
|
|
|
|
|
ElfSection* currentFrameSection = (info->ehFrame)
|
|
|
|
|
? fEHFrameSection : fDebugFrameSection;
|
|
|
|
|
|
|
|
|
|
if (currentFrameSection == NULL)
|
|
|
|
|
return B_ENTRY_NOT_FOUND;
|
|
|
|
|
|
|
|
|
|
bool gcc4EHFrameSection = false;
|
|
|
|
|
if (usingEHFrameSection) {
|
|
|
|
|
gcc4EHFrameSection = !currentFrameSection->IsWritable();
|
|
|
|
|
// Crude heuristic for recognizing GCC 4 (Itanium ABI) style
|
|
|
|
|
// .eh_frame sections. The ones generated by GCC 2 are writable,
|
|
|
|
|
// the ones generated by GCC 4 aren't.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE_CFI("DwarfFile::_UnwindCallFrame(%#" B_PRIx64 ")\n", location);
|
|
|
|
|
|
|
|
|
|
DataReader dataReader((uint8*)currentFrameSection->Data(),
|
|
|
|
|
currentFrameSection->Size(), unit != NULL
|
|
|
|
|
? unit->AddressSize() : addressSize);
|
|
|
|
|
dataReader.SeekAbsolute(info->fdeOffset);
|
|
|
|
|
|
|
|
|
|
while (dataReader.BytesRemaining() > 0) {
|
|
|
|
|
// length
|
|
|
|
|
bool dwarf64;
|
|
|
|
|
TRACE_CFI_ONLY(off_t entryOffset = dataReader.Offset();)
|
|
|
|
|
uint64 length = dataReader.ReadInitialLength(dwarf64);
|
|
|
|
|
bool dwarf64;
|
|
|
|
|
uint64 length = dataReader.ReadInitialLength(dwarf64);
|
|
|
|
|
uint64 lengthOffset = dataReader.Offset();
|
|
|
|
|
|
|
|
|
|
TRACE_CFI("DwarfFile::_UnwindCallFrame(): offset: %" B_PRIdOFF
|
|
|
|
|
", length: %" B_PRId64 "\n", entryOffset, length);
|
|
|
|
|
CfaContext context;
|
|
|
|
|
CIEAugmentation cieAugmentation;
|
|
|
|
|
// when using .eh_frame format, we need to parse the CIE's
|
|
|
|
|
// augmentation up front in order to know how the FDE's addresses
|
|
|
|
|
// will be represented
|
|
|
|
|
DataReader cieReader;
|
|
|
|
|
off_t cieRemaining;
|
|
|
|
|
status_t error = _ParseCIEHeader(currentFrameSection,
|
|
|
|
|
info->ehFrame, unit, addressSize, context, info->cieOffset,
|
|
|
|
|
cieAugmentation, cieReader, cieRemaining);
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
if (cieReader.HasOverflow())
|
|
|
|
|
return B_BAD_DATA;
|
|
|
|
|
if (cieRemaining < 0)
|
|
|
|
|
return B_BAD_DATA;
|
|
|
|
|
|
|
|
|
|
if (length > (uint64)dataReader.BytesRemaining())
|
|
|
|
|
return B_BAD_DATA;
|
|
|
|
|
off_t lengthOffset = dataReader.Offset();
|
|
|
|
|
uint64 remaining = lengthOffset + length - info->fdeOffset;
|
|
|
|
|
if (remaining < 0)
|
|
|
|
|
return B_BAD_DATA;
|
|
|
|
|
|
|
|
|
|
// CIE ID/CIE pointer
|
|
|
|
|
uint64 cieID = dwarf64
|
|
|
|
|
? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
|
|
|
|
|
// skip CIE ID, initial offset and range, since we already know those
|
|
|
|
|
// from FDELookupInfo.
|
|
|
|
|
dwarf64 ? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
|
|
|
|
|
cieAugmentation.ReadEncodedAddress(dataReader, fElfFile,
|
|
|
|
|
currentFrameSection);
|
|
|
|
|
cieAugmentation.ReadEncodedAddress(dataReader, fElfFile,
|
|
|
|
|
currentFrameSection, true);
|
|
|
|
|
|
|
|
|
|
// In .debug_frame ~0 indicates a CIE, in .eh_frame 0 does.
|
|
|
|
|
if (usingEHFrameSection
|
|
|
|
|
? cieID == 0
|
|
|
|
|
: (dwarf64
|
|
|
|
|
? cieID == 0xffffffffffffffffULL
|
|
|
|
|
: cieID == 0xffffffff)) {
|
|
|
|
|
// this is a CIE -- skip it
|
|
|
|
|
} else {
|
|
|
|
|
// this is a FDE
|
|
|
|
|
uint64 initialLocationOffset = dataReader.Offset();
|
|
|
|
|
// In .eh_frame the CIE offset is a relative back offset.
|
|
|
|
|
if (usingEHFrameSection) {
|
|
|
|
|
if (cieID > (uint64)lengthOffset) {
|
|
|
|
|
TRACE_CFI("Invalid CIE offset: %" B_PRIu64 ", max "
|
|
|
|
|
"possible: %" B_PRIu64 "\n", cieID, lengthOffset);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// convert to a section relative offset
|
|
|
|
|
cieID = lengthOffset - cieID;
|
|
|
|
|
}
|
|
|
|
|
TRACE_CFI(" found fde: length: %" B_PRIu64 " (%" B_PRIdOFF
|
|
|
|
|
"), CIE offset: %#" B_PRIx64 ", location: %#" B_PRIx64 ", "
|
|
|
|
|
"range: %#" B_PRIx64 "\n", length, dataReader.BytesRemaining(),
|
|
|
|
|
info->cieOffset, info->start, info->end - info->start);
|
|
|
|
|
|
|
|
|
|
context.SetLocation(location, info->start);
|
|
|
|
|
uint32 registerCount = outputInterface->CountRegisters();
|
|
|
|
|
error = context.Init(registerCount);
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
|
|
|
|
|
CfaContext context;
|
|
|
|
|
CIEAugmentation cieAugmentation;
|
|
|
|
|
// when using .eh_frame format, we need to parse the CIE's
|
|
|
|
|
// augmentation up front in order to know how the FDE's addresses
|
|
|
|
|
// will be represented
|
|
|
|
|
DataReader cieReader;
|
|
|
|
|
off_t cieRemaining;
|
|
|
|
|
status_t error = _ParseCIEHeader(currentFrameSection,
|
|
|
|
|
usingEHFrameSection, unit, addressSize, context, cieID,
|
|
|
|
|
cieAugmentation, cieReader, cieRemaining);
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
if (cieReader.HasOverflow())
|
|
|
|
|
return B_BAD_DATA;
|
|
|
|
|
if (cieRemaining < 0)
|
|
|
|
|
return B_BAD_DATA;
|
|
|
|
|
error = outputInterface->InitRegisterRules(context);
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
|
|
|
|
|
target_addr_t initialLocation = cieAugmentation.ReadEncodedAddress(
|
|
|
|
|
dataReader, fElfFile, currentFrameSection);
|
|
|
|
|
target_addr_t addressRange = cieAugmentation.ReadEncodedAddress(
|
|
|
|
|
dataReader, fElfFile, currentFrameSection, true);
|
|
|
|
|
// process the CIE's frame info instructions
|
|
|
|
|
cieReader = cieReader.RestrictedReader(cieRemaining);
|
|
|
|
|
error = _ParseFrameInfoInstructions(unit, context,
|
|
|
|
|
cieReader, cieAugmentation);
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
|
|
|
|
|
if (dataReader.HasOverflow())
|
|
|
|
|
return B_BAD_DATA;
|
|
|
|
|
|
|
|
|
|
if ((cieAugmentation.FDEAddressType()
|
|
|
|
|
& CFI_ADDRESS_TYPE_PC_RELATIVE) != 0) {
|
|
|
|
|
initialLocation += initialLocationOffset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: For GCC 2 .eh_frame sections things work differently: The
|
|
|
|
|
// initial locations are relocated by the runtime loader and
|
|
|
|
|
// afterwards point to the absolute addresses. Fortunately the
|
|
|
|
|
// relocations that always seem to be used are R_386_RELATIVE, so
|
|
|
|
|
// that the value we read from the file is already absolute
|
|
|
|
|
// (assuming an unchanged segment load address).
|
|
|
|
|
|
|
|
|
|
TRACE_CFI("location: %" B_PRIx64 ", initial location: %" B_PRIx64
|
|
|
|
|
", address range: %" B_PRIx64 "\n", location, initialLocation,
|
|
|
|
|
addressRange);
|
|
|
|
|
|
|
|
|
|
if (location >= initialLocation
|
|
|
|
|
&& location < initialLocation + addressRange) {
|
|
|
|
|
// This is the FDE we're looking for.
|
|
|
|
|
off_t remaining = lengthOffset + length
|
|
|
|
|
- dataReader.Offset();
|
|
|
|
|
if (remaining < 0)
|
|
|
|
|
return B_BAD_DATA;
|
|
|
|
|
|
|
|
|
|
TRACE_CFI(" found fde: length: %" B_PRIu64 " (%" B_PRIdOFF
|
|
|
|
|
"), CIE offset: %#" B_PRIx64 ", location: %#" B_PRIx64 ", "
|
|
|
|
|
"range: %#" B_PRIx64 "\n", length, remaining, cieID,
|
|
|
|
|
initialLocation, addressRange);
|
|
|
|
|
|
|
|
|
|
context.SetLocation(location, initialLocation);
|
|
|
|
|
uint32 registerCount = outputInterface->CountRegisters();
|
|
|
|
|
error = context.Init(registerCount);
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
|
|
|
|
|
error = outputInterface->InitRegisterRules(context);
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
|
|
|
|
|
// process the CIE's frame info instructions
|
|
|
|
|
cieReader = cieReader.RestrictedReader(cieRemaining);
|
|
|
|
|
error = _ParseFrameInfoInstructions(unit, context,
|
|
|
|
|
cieReader, cieAugmentation);
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
|
|
|
|
|
// read the FDE augmentation data (if any)
|
|
|
|
|
FDEAugmentation fdeAugmentation;
|
|
|
|
|
error = cieAugmentation.ReadFDEData(dataReader,
|
|
|
|
|
fdeAugmentation);
|
|
|
|
|
if (error != B_OK) {
|
|
|
|
|
TRACE_CFI(" failed to read FDE augmentation data!\n");
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
// adjust remaining byte count to take augmentation bytes
|
|
|
|
|
// (if any) into account.
|
|
|
|
|
remaining = lengthOffset + length
|
|
|
|
|
- dataReader.Offset();
|
|
|
|
|
|
|
|
|
|
error = context.SaveInitialRuleSet();
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
|
|
|
|
|
DataReader restrictedReader =
|
|
|
|
|
dataReader.RestrictedReader(remaining);
|
|
|
|
|
error = _ParseFrameInfoInstructions(unit, context,
|
|
|
|
|
restrictedReader, cieAugmentation);
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
|
|
|
|
|
TRACE_CFI(" found row!\n");
|
|
|
|
|
|
|
|
|
|
// apply the rules of the final row
|
|
|
|
|
// get the frameAddress first
|
|
|
|
|
target_addr_t frameAddress;
|
|
|
|
|
CfaCfaRule* cfaCfaRule = context.GetCfaCfaRule();
|
|
|
|
|
switch (cfaCfaRule->Type()) {
|
|
|
|
|
case CFA_CFA_RULE_REGISTER_OFFSET:
|
|
|
|
|
{
|
|
|
|
|
BVariant value;
|
|
|
|
|
if (!inputInterface->GetRegisterValue(
|
|
|
|
|
cfaCfaRule->Register(), value)
|
|
|
|
|
|| !value.IsNumber()) {
|
|
|
|
|
return B_UNSUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
frameAddress = value.ToUInt64() + cfaCfaRule->Offset();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CFA_CFA_RULE_EXPRESSION:
|
|
|
|
|
{
|
|
|
|
|
error = EvaluateExpression(unit, addressSize,
|
|
|
|
|
subprogramEntry,
|
|
|
|
|
cfaCfaRule->Expression().block,
|
|
|
|
|
cfaCfaRule->Expression().size,
|
|
|
|
|
inputInterface, location, 0, 0, false,
|
|
|
|
|
frameAddress);
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CFA_CFA_RULE_UNDEFINED:
|
|
|
|
|
default:
|
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE_CFI(" frame address: %#" B_PRIx64 "\n", frameAddress);
|
|
|
|
|
|
|
|
|
|
// apply the register rules
|
|
|
|
|
for (uint32 i = 0; i < registerCount; i++) {
|
|
|
|
|
TRACE_CFI(" reg %" B_PRIu32 "\n", i);
|
|
|
|
|
|
|
|
|
|
uint32 valueType = outputInterface->RegisterValueType(i);
|
|
|
|
|
if (valueType == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
CfaRule* rule = context.RegisterRule(i);
|
|
|
|
|
if (rule == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// apply the rule
|
|
|
|
|
switch (rule->Type()) {
|
|
|
|
|
case CFA_RULE_SAME_VALUE:
|
|
|
|
|
{
|
|
|
|
|
TRACE_CFI(" -> CFA_RULE_SAME_VALUE\n");
|
|
|
|
|
|
|
|
|
|
BVariant value;
|
|
|
|
|
if (inputInterface->GetRegisterValue(i, value))
|
|
|
|
|
outputInterface->SetRegisterValue(i, value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CFA_RULE_LOCATION_OFFSET:
|
|
|
|
|
{
|
|
|
|
|
TRACE_CFI(" -> CFA_RULE_LOCATION_OFFSET: %"
|
|
|
|
|
B_PRId64 "\n", rule->Offset());
|
|
|
|
|
|
|
|
|
|
BVariant value;
|
|
|
|
|
if (inputInterface->ReadValueFromMemory(
|
|
|
|
|
frameAddress + rule->Offset(), valueType,
|
|
|
|
|
value)) {
|
|
|
|
|
outputInterface->SetRegisterValue(i, value);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CFA_RULE_VALUE_OFFSET:
|
|
|
|
|
TRACE_CFI(" -> CFA_RULE_VALUE_OFFSET\n");
|
|
|
|
|
|
|
|
|
|
outputInterface->SetRegisterValue(i,
|
|
|
|
|
frameAddress + rule->Offset());
|
|
|
|
|
break;
|
|
|
|
|
case CFA_RULE_REGISTER:
|
|
|
|
|
{
|
|
|
|
|
TRACE_CFI(" -> CFA_RULE_REGISTER\n");
|
|
|
|
|
|
|
|
|
|
BVariant value;
|
|
|
|
|
if (inputInterface->GetRegisterValue(
|
|
|
|
|
rule->Register(), value)) {
|
|
|
|
|
outputInterface->SetRegisterValue(i, value);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CFA_RULE_LOCATION_EXPRESSION:
|
|
|
|
|
{
|
|
|
|
|
TRACE_CFI(" -> CFA_RULE_LOCATION_EXPRESSION\n");
|
|
|
|
|
|
|
|
|
|
target_addr_t address;
|
|
|
|
|
error = EvaluateExpression(unit, addressSize,
|
|
|
|
|
subprogramEntry,
|
|
|
|
|
rule->Expression().block,
|
|
|
|
|
rule->Expression().size,
|
|
|
|
|
inputInterface, location, frameAddress,
|
|
|
|
|
frameAddress, true, address);
|
|
|
|
|
BVariant value;
|
|
|
|
|
if (error == B_OK
|
|
|
|
|
&& inputInterface->ReadValueFromMemory(address,
|
|
|
|
|
valueType, value)) {
|
|
|
|
|
outputInterface->SetRegisterValue(i, value);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CFA_RULE_VALUE_EXPRESSION:
|
|
|
|
|
{
|
|
|
|
|
TRACE_CFI(" -> CFA_RULE_VALUE_EXPRESSION\n");
|
|
|
|
|
|
|
|
|
|
target_addr_t value;
|
|
|
|
|
error = EvaluateExpression(unit, addressSize,
|
|
|
|
|
subprogramEntry,
|
|
|
|
|
rule->Expression().block,
|
|
|
|
|
rule->Expression().size,
|
|
|
|
|
inputInterface, location, frameAddress,
|
|
|
|
|
frameAddress, true, value);
|
|
|
|
|
if (error == B_OK)
|
|
|
|
|
outputInterface->SetRegisterValue(i, value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CFA_RULE_UNDEFINED:
|
|
|
|
|
TRACE_CFI(" -> CFA_RULE_UNDEFINED\n");
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_framePointer = frameAddress;
|
|
|
|
|
return B_OK;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dataReader.SeekAbsolute(lengthOffset + length);
|
|
|
|
|
// read the FDE augmentation data (if any)
|
|
|
|
|
FDEAugmentation fdeAugmentation;
|
|
|
|
|
error = cieAugmentation.ReadFDEData(dataReader,
|
|
|
|
|
fdeAugmentation);
|
|
|
|
|
if (error != B_OK) {
|
|
|
|
|
TRACE_CFI(" failed to read FDE augmentation data!\n");
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return B_ENTRY_NOT_FOUND;
|
|
|
|
|
error = context.SaveInitialRuleSet();
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
|
|
|
|
|
DataReader restrictedReader =
|
|
|
|
|
dataReader.RestrictedReader(remaining);
|
|
|
|
|
error = _ParseFrameInfoInstructions(unit, context,
|
|
|
|
|
restrictedReader, cieAugmentation);
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
|
|
|
|
|
TRACE_CFI(" found row!\n");
|
|
|
|
|
|
|
|
|
|
// apply the rules of the final row
|
|
|
|
|
// get the frameAddress first
|
|
|
|
|
target_addr_t frameAddress;
|
|
|
|
|
CfaCfaRule* cfaCfaRule = context.GetCfaCfaRule();
|
|
|
|
|
switch (cfaCfaRule->Type()) {
|
|
|
|
|
case CFA_CFA_RULE_REGISTER_OFFSET:
|
|
|
|
|
{
|
|
|
|
|
BVariant value;
|
|
|
|
|
if (!inputInterface->GetRegisterValue(
|
|
|
|
|
cfaCfaRule->Register(), value)
|
|
|
|
|
|| !value.IsNumber()) {
|
|
|
|
|
return B_UNSUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
frameAddress = value.ToUInt64() + cfaCfaRule->Offset();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CFA_CFA_RULE_EXPRESSION:
|
|
|
|
|
{
|
|
|
|
|
error = EvaluateExpression(unit, addressSize,
|
|
|
|
|
subprogramEntry,
|
|
|
|
|
cfaCfaRule->Expression().block,
|
|
|
|
|
cfaCfaRule->Expression().size,
|
|
|
|
|
inputInterface, location, 0, 0, false,
|
|
|
|
|
frameAddress);
|
|
|
|
|
if (error != B_OK)
|
|
|
|
|
return error;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CFA_CFA_RULE_UNDEFINED:
|
|
|
|
|
default:
|
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE_CFI(" frame address: %#" B_PRIx64 "\n", frameAddress);
|
|
|
|
|
|
|
|
|
|
// apply the register rules
|
|
|
|
|
for (uint32 i = 0; i < registerCount; i++) {
|
|
|
|
|
TRACE_CFI(" reg %" B_PRIu32 "\n", i);
|
|
|
|
|
|
|
|
|
|
uint32 valueType = outputInterface->RegisterValueType(i);
|
|
|
|
|
if (valueType == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
CfaRule* rule = context.RegisterRule(i);
|
|
|
|
|
if (rule == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// apply the rule
|
|
|
|
|
switch (rule->Type()) {
|
|
|
|
|
case CFA_RULE_SAME_VALUE:
|
|
|
|
|
{
|
|
|
|
|
TRACE_CFI(" -> CFA_RULE_SAME_VALUE\n");
|
|
|
|
|
|
|
|
|
|
BVariant value;
|
|
|
|
|
if (inputInterface->GetRegisterValue(i, value))
|
|
|
|
|
outputInterface->SetRegisterValue(i, value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CFA_RULE_LOCATION_OFFSET:
|
|
|
|
|
{
|
|
|
|
|
TRACE_CFI(" -> CFA_RULE_LOCATION_OFFSET: %"
|
|
|
|
|
B_PRId64 "\n", rule->Offset());
|
|
|
|
|
|
|
|
|
|
BVariant value;
|
|
|
|
|
if (inputInterface->ReadValueFromMemory(
|
|
|
|
|
frameAddress + rule->Offset(), valueType,
|
|
|
|
|
value)) {
|
|
|
|
|
outputInterface->SetRegisterValue(i, value);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CFA_RULE_VALUE_OFFSET:
|
|
|
|
|
TRACE_CFI(" -> CFA_RULE_VALUE_OFFSET\n");
|
|
|
|
|
|
|
|
|
|
outputInterface->SetRegisterValue(i,
|
|
|
|
|
frameAddress + rule->Offset());
|
|
|
|
|
break;
|
|
|
|
|
case CFA_RULE_REGISTER:
|
|
|
|
|
{
|
|
|
|
|
TRACE_CFI(" -> CFA_RULE_REGISTER\n");
|
|
|
|
|
|
|
|
|
|
BVariant value;
|
|
|
|
|
if (inputInterface->GetRegisterValue(
|
|
|
|
|
rule->Register(), value)) {
|
|
|
|
|
outputInterface->SetRegisterValue(i, value);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CFA_RULE_LOCATION_EXPRESSION:
|
|
|
|
|
{
|
|
|
|
|
TRACE_CFI(" -> CFA_RULE_LOCATION_EXPRESSION\n");
|
|
|
|
|
|
|
|
|
|
target_addr_t address;
|
|
|
|
|
error = EvaluateExpression(unit, addressSize,
|
|
|
|
|
subprogramEntry,
|
|
|
|
|
rule->Expression().block,
|
|
|
|
|
rule->Expression().size,
|
|
|
|
|
inputInterface, location, frameAddress,
|
|
|
|
|
frameAddress, true, address);
|
|
|
|
|
BVariant value;
|
|
|
|
|
if (error == B_OK
|
|
|
|
|
&& inputInterface->ReadValueFromMemory(address,
|
|
|
|
|
valueType, value)) {
|
|
|
|
|
outputInterface->SetRegisterValue(i, value);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CFA_RULE_VALUE_EXPRESSION:
|
|
|
|
|
{
|
|
|
|
|
TRACE_CFI(" -> CFA_RULE_VALUE_EXPRESSION\n");
|
|
|
|
|
|
|
|
|
|
target_addr_t value;
|
|
|
|
|
error = EvaluateExpression(unit, addressSize,
|
|
|
|
|
subprogramEntry,
|
|
|
|
|
rule->Expression().block,
|
|
|
|
|
rule->Expression().size,
|
|
|
|
|
inputInterface, location, frameAddress,
|
|
|
|
|
frameAddress, true, value);
|
|
|
|
|
if (error == B_OK)
|
|
|
|
|
outputInterface->SetRegisterValue(i, value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CFA_RULE_UNDEFINED:
|
|
|
|
|
TRACE_CFI(" -> CFA_RULE_UNDEFINED\n");
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_framePointer = frameAddress;
|
|
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2842,3 +2926,40 @@ DwarfFile::_GetContainingCompilationUnit(off_t refAddr) const
|
|
|
|
|
CompilationUnit* unit = fCompilationUnits.ItemAt(lower);
|
|
|
|
|
return unit->ContainsAbsoluteOffset(refAddr) ? unit : NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DwarfFile::FDELookupInfo*
|
|
|
|
|
DwarfFile::_GetContainingFDEInfo(target_addr_t offset) const
|
|
|
|
|
{
|
|
|
|
|
FDELookupInfo* info = NULL;
|
|
|
|
|
if (fDebugFrameSection != NULL) {
|
|
|
|
|
info = _GetContainingFDEInfo(offset, fDebugFrameInfos);
|
|
|
|
|
if (info != NULL)
|
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _GetContainingFDEInfo(offset, fEHFrameInfos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DwarfFile::FDELookupInfo*
|
|
|
|
|
DwarfFile::_GetContainingFDEInfo(target_addr_t offset,
|
|
|
|
|
const FDEInfoList& infoList) const
|
|
|
|
|
{
|
|
|
|
|
// binary search
|
|
|
|
|
int lower = 0;
|
|
|
|
|
int upper = infoList.CountItems() - 1;
|
|
|
|
|
if (upper < 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
while (lower < upper) {
|
|
|
|
|
int mid = (lower + upper + 1) / 2;
|
|
|
|
|
if (offset < infoList.ItemAt(mid)->start)
|
|
|
|
|
upper = mid - 1;
|
|
|
|
|
else
|
|
|
|
|
lower = mid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FDELookupInfo* info = infoList.ItemAt(lower);
|
|
|
|
|
return info->ContainsAddress(offset) ? info : NULL;
|
|
|
|
|
}
|
|
|
|
|