mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-06 14:44:26 +00:00
Bug 788974 - Don't disable elfhack when enabling profiling on platforms supporting dl_iterate_phdr. r=glandium.
This commit is contained in:
parent
d0efa48997
commit
63a104efba
@ -238,13 +238,13 @@ template<typename ElfClass>
|
||||
bool LoadARMexidx(const typename ElfClass::Ehdr* elf_header,
|
||||
const typename ElfClass::Shdr* exidx_section,
|
||||
const typename ElfClass::Shdr* extab_section,
|
||||
uint32_t loading_addr,
|
||||
uintptr_t text_bias,
|
||||
uintptr_t rx_avma, size_t rx_size,
|
||||
SecMap* smap,
|
||||
void (*log)(const char*)) {
|
||||
// To do this properly we need to know:
|
||||
// * the bounds of the .ARM.exidx section in the mapped image
|
||||
// * the bounds of the .ARM.extab section in the mapped image
|
||||
// * the bounds of the .ARM.exidx section in the process image
|
||||
// * the bounds of the .ARM.extab section in the process image
|
||||
// * the vma of the last byte in the text section associated with the .exidx
|
||||
// The first two are easy. The third is a bit tricky. If we can't
|
||||
// figure out what it is, just pass in zero.
|
||||
@ -258,18 +258,46 @@ bool LoadARMexidx(const typename ElfClass::Ehdr* elf_header,
|
||||
// though .extab is missing, the range checks done by GET_EX_U32 in
|
||||
// ExceptionTableInfo::ExtabEntryExtract should prevent any invalid
|
||||
// memory accesses, and cause the .extab to be rejected as invalid.
|
||||
const char *exidx_img
|
||||
= GetOffset<ElfClass, char>(elf_header, exidx_section->sh_offset);
|
||||
size_t exidx_size = exidx_section->sh_size;
|
||||
const char *extab_img
|
||||
= extab_section
|
||||
? GetOffset<ElfClass, char>(elf_header, extab_section->sh_offset)
|
||||
: nullptr;
|
||||
size_t extab_size = extab_section ? extab_section->sh_size : 0;
|
||||
|
||||
uintptr_t exidx_svma = exidx_section->sh_addr;
|
||||
uintptr_t exidx_avma = exidx_svma + text_bias;
|
||||
size_t exidx_size = exidx_section->sh_size;
|
||||
|
||||
uintptr_t extab_svma = 0;
|
||||
uintptr_t extab_avma = 0;
|
||||
size_t extab_size = 0;
|
||||
if (extab_section) {
|
||||
extab_svma = extab_section->sh_addr;
|
||||
extab_avma = extab_svma + text_bias;
|
||||
extab_size = extab_section->sh_size;
|
||||
}
|
||||
|
||||
// Because we are reading EXIDX directly out of the executing image,
|
||||
// we need to be careful to check that the relevant sections have
|
||||
// really been mapped with r permissions, so as to guarantee that
|
||||
// reading them won't segfault. Do this by checking that rx mapped
|
||||
// area covers the exidx and extab as mapped in.
|
||||
|
||||
if (rx_size == 0)
|
||||
// This seems sufficiently bogus that we shouldn't proceed further.
|
||||
return false;
|
||||
|
||||
if (exidx_size == 0)
|
||||
// There's no EXIDX data. No point in continuing.
|
||||
return false;
|
||||
|
||||
if (!(exidx_avma >= rx_avma && exidx_avma + exidx_size <= rx_avma + rx_size))
|
||||
// The mapped .exidx isn't entirely inside the rx area.
|
||||
return false;
|
||||
|
||||
if (extab_section &&
|
||||
!(extab_avma >= rx_avma && extab_avma + extab_size <= rx_avma + rx_size))
|
||||
// There an .extab section, but it isn't entirely inside the rx area.
|
||||
return false;
|
||||
|
||||
// The sh_link field of the exidx section gives the section number
|
||||
// for the associated text section.
|
||||
uint32_t exidx_text_last_svma = 0;
|
||||
uint32_t exidx_text_last_avma = 0;
|
||||
int exidx_text_sno = exidx_section->sh_link;
|
||||
typedef typename ElfClass::Shdr Shdr;
|
||||
// |sections| points to the section header table
|
||||
@ -279,17 +307,18 @@ bool LoadARMexidx(const typename ElfClass::Ehdr* elf_header,
|
||||
if (exidx_text_sno >= 0 && exidx_text_sno < num_sections) {
|
||||
const Shdr* exidx_text_shdr = §ions[exidx_text_sno];
|
||||
if (exidx_text_shdr->sh_size > 0) {
|
||||
exidx_text_last_svma
|
||||
uint32_t exidx_text_last_svma
|
||||
= exidx_text_shdr->sh_addr + exidx_text_shdr->sh_size - 1;
|
||||
exidx_text_last_avma
|
||||
= exidx_text_last_svma + text_bias;
|
||||
}
|
||||
}
|
||||
|
||||
lul::ARMExToModule handler(smap, log);
|
||||
lul::ExceptionTableInfo
|
||||
parser(exidx_img, exidx_size, extab_img, extab_size, exidx_text_last_svma,
|
||||
&handler,
|
||||
reinterpret_cast<const char*>(elf_header),
|
||||
loading_addr, text_bias, log);
|
||||
parser(reinterpret_cast<const char*>(exidx_avma), exidx_size,
|
||||
reinterpret_cast<const char*>(extab_avma), extab_size,
|
||||
exidx_text_last_avma, &handler, log);
|
||||
parser.Start();
|
||||
return true;
|
||||
}
|
||||
@ -417,7 +446,7 @@ bool LoadSymbols(const string& obj_file,
|
||||
const bool read_gnu_debug_link,
|
||||
LoadSymbolsInfo<ElfClass>* info,
|
||||
SecMap* smap,
|
||||
void* rx_avma,
|
||||
void* rx_avma, size_t rx_size,
|
||||
void (*log)(const char*)) {
|
||||
typedef typename ElfClass::Phdr Phdr;
|
||||
typedef typename ElfClass::Shdr Shdr;
|
||||
@ -523,7 +552,9 @@ bool LoadSymbols(const string& obj_file,
|
||||
info->LoadedSection(".ARM.extab");
|
||||
bool result = LoadARMexidx<ElfClass>(elf_header,
|
||||
arm_exidx_section, arm_extab_section,
|
||||
loading_addr, text_bias, smap, log);
|
||||
text_bias,
|
||||
reinterpret_cast<uintptr_t>(rx_avma),
|
||||
rx_size, smap, log);
|
||||
found_usable_info = found_usable_info || result;
|
||||
if (result)
|
||||
log("LoadSymbols: read EXIDX from .ARM.{exidx,extab}");
|
||||
@ -590,7 +621,7 @@ template<typename ElfClass>
|
||||
bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
|
||||
const string& obj_filename,
|
||||
const vector<string>& debug_dirs,
|
||||
SecMap* smap, void* rx_avma,
|
||||
SecMap* smap, void* rx_avma, size_t rx_size,
|
||||
void (*log)(const char*)) {
|
||||
typedef typename ElfClass::Ehdr Ehdr;
|
||||
|
||||
@ -621,7 +652,7 @@ bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
|
||||
LoadSymbolsInfo<ElfClass> info(debug_dirs);
|
||||
if (!LoadSymbols<ElfClass>(obj_filename, big_endian, elf_header,
|
||||
!debug_dirs.empty(), &info,
|
||||
smap, rx_avma, log)) {
|
||||
smap, rx_avma, rx_size, log)) {
|
||||
const string debuglink_file = info.debuglink_file();
|
||||
if (debuglink_file.empty())
|
||||
return false;
|
||||
@ -660,7 +691,7 @@ bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
|
||||
|
||||
if (!LoadSymbols<ElfClass>(debuglink_file, debug_big_endian,
|
||||
debug_elf_header, false, &info,
|
||||
smap, rx_avma, log)) {
|
||||
smap, rx_avma, rx_size, log)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -676,7 +707,7 @@ namespace lul {
|
||||
bool ReadSymbolDataInternal(const uint8_t* obj_file,
|
||||
const string& obj_filename,
|
||||
const vector<string>& debug_dirs,
|
||||
SecMap* smap, void* rx_avma,
|
||||
SecMap* smap, void* rx_avma, size_t rx_size,
|
||||
void (*log)(const char*)) {
|
||||
|
||||
if (!IsValidElf(obj_file)) {
|
||||
@ -688,12 +719,12 @@ bool ReadSymbolDataInternal(const uint8_t* obj_file,
|
||||
if (elfclass == ELFCLASS32) {
|
||||
return ReadSymbolDataElfClass<ElfClass32>(
|
||||
reinterpret_cast<const Elf32_Ehdr*>(obj_file),
|
||||
obj_filename, debug_dirs, smap, rx_avma, log);
|
||||
obj_filename, debug_dirs, smap, rx_avma, rx_size, log);
|
||||
}
|
||||
if (elfclass == ELFCLASS64) {
|
||||
return ReadSymbolDataElfClass<ElfClass64>(
|
||||
reinterpret_cast<const Elf64_Ehdr*>(obj_file),
|
||||
obj_filename, debug_dirs, smap, rx_avma, log);
|
||||
obj_filename, debug_dirs, smap, rx_avma, rx_size, log);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -701,7 +732,7 @@ bool ReadSymbolDataInternal(const uint8_t* obj_file,
|
||||
|
||||
bool ReadSymbolData(const string& obj_file,
|
||||
const vector<string>& debug_dirs,
|
||||
SecMap* smap, void* rx_avma,
|
||||
SecMap* smap, void* rx_avma, size_t rx_size,
|
||||
void (*log)(const char*)) {
|
||||
MmapWrapper map_wrapper;
|
||||
void* elf_header = NULL;
|
||||
@ -709,7 +740,8 @@ bool ReadSymbolData(const string& obj_file,
|
||||
return false;
|
||||
|
||||
return ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(elf_header),
|
||||
obj_file, debug_dirs, smap, rx_avma, log);
|
||||
obj_file, debug_dirs,
|
||||
smap, rx_avma, rx_size, log);
|
||||
}
|
||||
|
||||
|
||||
|
@ -50,7 +50,8 @@ namespace lul {
|
||||
// or shared library, and add it to SMAP.
|
||||
bool ReadSymbolData(const std::string& obj_file,
|
||||
const std::vector<std::string>& debug_dirs,
|
||||
SecMap* smap, void* rx_avma,
|
||||
SecMap* smap,
|
||||
void* rx_avma, size_t rx_size,
|
||||
void (*log)(const char*));
|
||||
|
||||
// The same as ReadSymbolData, except that OBJ_FILE is assumed to
|
||||
@ -58,7 +59,8 @@ bool ReadSymbolData(const std::string& obj_file,
|
||||
bool ReadSymbolDataInternal(const uint8_t* obj_file,
|
||||
const std::string& obj_filename,
|
||||
const std::vector<std::string>& debug_dirs,
|
||||
SecMap* smap, void* rx_avma,
|
||||
SecMap* smap,
|
||||
void* rx_avma, size_t rx_size,
|
||||
void (*log)(const char*));
|
||||
|
||||
} // namespace lul
|
||||
|
@ -325,9 +325,9 @@ ExceptionTableInfo::ExtabEntryExtract(const struct exidx_entry* entry,
|
||||
(_lval) = *(reinterpret_cast<const uint32_t*>(_addr)); } while (0)
|
||||
|
||||
# define GET_EXIDX_U32(_lval, _addr) \
|
||||
GET_EX_U32(_lval, _addr, mr_exidx_)
|
||||
GET_EX_U32(_lval, _addr, mr_exidx_avma_)
|
||||
# define GET_EXTAB_U32(_lval, _addr) \
|
||||
GET_EX_U32(_lval, _addr, mr_extab_)
|
||||
GET_EX_U32(_lval, _addr, mr_extab_avma_)
|
||||
|
||||
uint32_t data;
|
||||
GET_EXIDX_U32(data, &entry->data);
|
||||
@ -575,10 +575,10 @@ int ExceptionTableInfo::ExtabEntryDecode(const uint8_t* buf, size_t buf_size)
|
||||
void ExceptionTableInfo::Start()
|
||||
{
|
||||
const struct exidx_entry* start
|
||||
= reinterpret_cast<const struct exidx_entry*>(mr_exidx_.data());
|
||||
= reinterpret_cast<const struct exidx_entry*>(mr_exidx_avma_.data());
|
||||
const struct exidx_entry* end
|
||||
= reinterpret_cast<const struct exidx_entry*>(mr_exidx_.data()
|
||||
+ mr_exidx_.length());
|
||||
= reinterpret_cast<const struct exidx_entry*>(mr_exidx_avma_.data()
|
||||
+ mr_exidx_avma_.length());
|
||||
|
||||
// Iterate over each of the EXIDX entries (pairs of 32-bit words).
|
||||
// These occupy the entire .exidx section.
|
||||
@ -586,17 +586,11 @@ void ExceptionTableInfo::Start()
|
||||
|
||||
// Figure out the code address range that this table entry is
|
||||
// associated with.
|
||||
//
|
||||
// I don't claim to understand the biasing here. It appears that
|
||||
// (Prel31ToAddr(&entry->addr))
|
||||
// - mapping_addr_ + loading_addr_) & 0x7fffffff
|
||||
// produces a SVMA. Adding the text_bias_ gives plausible AVMAs.
|
||||
uint32_t svma = (reinterpret_cast<char*>(Prel31ToAddr(&entry->addr))
|
||||
- mapping_addr_ + loading_addr_) & 0x7fffffff;
|
||||
uint32_t next_svma;
|
||||
uint32_t avma = reinterpret_cast<uint32_t>(Prel31ToAddr(&entry->addr));
|
||||
uint32_t next_avma;
|
||||
if (entry < end - 1) {
|
||||
next_svma = (reinterpret_cast<char*>(Prel31ToAddr(&((entry + 1)->addr)))
|
||||
- mapping_addr_ + loading_addr_) & 0x7fffffff;
|
||||
next_avma
|
||||
= reinterpret_cast<uint32_t>(Prel31ToAddr(&((entry + 1)->addr)));
|
||||
} else {
|
||||
// This is the last EXIDX entry in the sequence, so we don't
|
||||
// have an address for the start of the next function, to limit
|
||||
@ -604,28 +598,30 @@ void ExceptionTableInfo::Start()
|
||||
// text section associated with this .exidx section, that we
|
||||
// have been given. So as to avoid junking up the CFI unwind
|
||||
// tables with absurdly large address ranges in the case where
|
||||
// text_last_svma_ is wrong, only use the value if it is nonzero
|
||||
// and within one page of |svma|. Otherwise assume a length of 1.
|
||||
// text_last_avma_ is wrong, only use the value if it is nonzero
|
||||
// and within one page of |avma|. Otherwise assume a length of 1.
|
||||
//
|
||||
// In some cases, gcc has been observed to finish the exidx
|
||||
// section with an entry of length 1 marked CANT_UNWIND,
|
||||
// presumably exactly for the purpose of giving a definite
|
||||
// length for the last real entry, without having to look at
|
||||
// text segment boundaries.
|
||||
bool plausible = false;
|
||||
next_svma = svma + 1;
|
||||
if (text_last_svma_ != 0) {
|
||||
uint32_t maybe_next_svma = text_last_svma_ + 1;
|
||||
if (maybe_next_svma > svma && maybe_next_svma - svma <= 4096) {
|
||||
next_svma = maybe_next_svma;
|
||||
plausible = true;
|
||||
}
|
||||
|
||||
bool plausible;
|
||||
uint32_t maybe_next_avma = text_last_avma_ + 1;
|
||||
if (maybe_next_avma > avma && maybe_next_avma - avma <= 4096) {
|
||||
next_avma = maybe_next_avma;
|
||||
plausible = true;
|
||||
} else {
|
||||
next_avma = avma + 1;
|
||||
plausible = false;
|
||||
}
|
||||
if (!plausible) {
|
||||
|
||||
if (!plausible && avma != text_last_avma_ + 1) {
|
||||
char buf[100];
|
||||
snprintf(buf, sizeof(buf),
|
||||
"ExceptionTableInfo: implausible EXIDX last entry size %d"
|
||||
"; using 1 instead.", (int32_t)(text_last_svma_ - svma));
|
||||
"; using 1 instead.", (int32_t)(text_last_avma_ - avma));
|
||||
buf[sizeof(buf)-1] = 0;
|
||||
log_(buf);
|
||||
}
|
||||
@ -672,7 +668,7 @@ void ExceptionTableInfo::Start()
|
||||
// create CFI entries that Breakpad can use. This can also fail.
|
||||
// First, add a new stack frame entry, into which ExtabEntryDecode
|
||||
// will write the CFI entries.
|
||||
handler_->AddStackFrame(svma + text_bias_, next_svma - svma);
|
||||
handler_->AddStackFrame(avma, next_avma - avma);
|
||||
int ret = ExtabEntryDecode(buf, buf_used);
|
||||
if (ret < 0) {
|
||||
handler_->DeleteStackFrame();
|
||||
|
@ -179,20 +179,15 @@ class MemoryRange {
|
||||
// from .ARM.exidx and .ARM.extab sections.
|
||||
class ExceptionTableInfo {
|
||||
public:
|
||||
ExceptionTableInfo(const char* exidx, size_t exidx_size,
|
||||
const char* extab, size_t extab_size,
|
||||
uint32_t text_last_svma,
|
||||
ExceptionTableInfo(const char* exidx_avma, size_t exidx_size,
|
||||
const char* extab_avma, size_t extab_size,
|
||||
uint32_t text_last_avma,
|
||||
lul::ARMExToModule* handler,
|
||||
const char* mapping_addr,
|
||||
uint32_t loading_addr,
|
||||
uintptr_t text_bias,
|
||||
void (*log)(const char*))
|
||||
: mr_exidx_(lul::MemoryRange(exidx, exidx_size)),
|
||||
mr_extab_(lul::MemoryRange(extab, extab_size)),
|
||||
text_last_svma_(text_last_svma),
|
||||
handler_(handler), mapping_addr_(mapping_addr),
|
||||
loading_addr_(loading_addr),
|
||||
text_bias_(text_bias),
|
||||
: mr_exidx_avma_(lul::MemoryRange(exidx_avma, exidx_size)),
|
||||
mr_extab_avma_(lul::MemoryRange(extab_avma, extab_size)),
|
||||
text_last_avma_(text_last_avma),
|
||||
handler_(handler),
|
||||
log_(log) { }
|
||||
|
||||
~ExceptionTableInfo() { }
|
||||
@ -203,13 +198,12 @@ class ExceptionTableInfo {
|
||||
void Start();
|
||||
|
||||
private:
|
||||
lul::MemoryRange mr_exidx_;
|
||||
lul::MemoryRange mr_extab_;
|
||||
uint32_t text_last_svma_;
|
||||
// Memory ranges for the exidx and extab sections in the executing image
|
||||
lul::MemoryRange mr_exidx_avma_;
|
||||
lul::MemoryRange mr_extab_avma_;
|
||||
// Address of the last byte of the text segment in the executing image
|
||||
uint32_t text_last_avma_;
|
||||
lul::ARMExToModule* handler_;
|
||||
const char* mapping_addr_;
|
||||
uint32_t loading_addr_;
|
||||
uintptr_t text_bias_;
|
||||
// debugging message sink
|
||||
void (*log_)(const char*);
|
||||
enum ExExtractResult {
|
||||
|
@ -974,12 +974,12 @@ LUL::NotifyAfterMap(uintptr_t aRXavma, size_t aSize,
|
||||
if (!aMappedImage) {
|
||||
(void)lul::ReadSymbolData(
|
||||
string(aFileName), std::vector<string>(), smap,
|
||||
(void*)aRXavma, mLog);
|
||||
(void*)aRXavma, aSize, mLog);
|
||||
} else {
|
||||
(void)lul::ReadSymbolDataInternal(
|
||||
(const uint8_t*)aMappedImage,
|
||||
string(aFileName), std::vector<string>(), smap,
|
||||
(void*)aRXavma, mLog);
|
||||
(void*)aRXavma, aSize, mLog);
|
||||
}
|
||||
|
||||
mLog("NotifyMap .. preparing entries\n");
|
||||
|
Loading…
x
Reference in New Issue
Block a user