зеркало из https://github.com/mozilla/gecko-dev.git
Bug 822584 - Workaround in elfhack to accomodate for breakpad not handling the memory mapping induced by the elfhack/bionic linker combination. r=nfroyd,a=akeybl
--HG-- extra : transplant_source : %E0%17%F3%A2m%1ASd%11%01%0E2%D6%C2%C3%D0h%8E%CF%3B
This commit is contained in:
Родитель
987dc92252
Коммит
d16fd4e0d9
|
@ -585,7 +585,7 @@ void ElfSegment::removeSection(ElfSection *section)
|
||||||
|
|
||||||
unsigned int ElfSegment::getFileSize()
|
unsigned int ElfSegment::getFileSize()
|
||||||
{
|
{
|
||||||
if (type == PT_GNU_RELRO)
|
if (type == PT_GNU_RELRO || isElfHackFillerSegment())
|
||||||
return filesz;
|
return filesz;
|
||||||
|
|
||||||
if (sections.empty())
|
if (sections.empty())
|
||||||
|
@ -604,7 +604,7 @@ unsigned int ElfSegment::getFileSize()
|
||||||
|
|
||||||
unsigned int ElfSegment::getMemSize()
|
unsigned int ElfSegment::getMemSize()
|
||||||
{
|
{
|
||||||
if (type == PT_GNU_RELRO)
|
if (type == PT_GNU_RELRO || isElfHackFillerSegment())
|
||||||
return memsz;
|
return memsz;
|
||||||
|
|
||||||
if (sections.empty())
|
if (sections.empty())
|
||||||
|
@ -621,6 +621,10 @@ unsigned int ElfSegment::getOffset()
|
||||||
(sections.front()->getAddr() != vaddr))
|
(sections.front()->getAddr() != vaddr))
|
||||||
throw std::runtime_error("PT_GNU_RELRO segment doesn't start on a section start");
|
throw std::runtime_error("PT_GNU_RELRO segment doesn't start on a section start");
|
||||||
|
|
||||||
|
// Neither bionic nor glibc linkers seem to like when the offset of that segment is 0
|
||||||
|
if (isElfHackFillerSegment())
|
||||||
|
return vaddr;
|
||||||
|
|
||||||
return sections.empty() ? 0 : sections.front()->getOffset();
|
return sections.empty() ? 0 : sections.front()->getOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,6 +634,9 @@ unsigned int ElfSegment::getAddr()
|
||||||
(sections.front()->getAddr() != vaddr))
|
(sections.front()->getAddr() != vaddr))
|
||||||
throw std::runtime_error("PT_GNU_RELRO segment doesn't start on a section start");
|
throw std::runtime_error("PT_GNU_RELRO segment doesn't start on a section start");
|
||||||
|
|
||||||
|
if (isElfHackFillerSegment())
|
||||||
|
return vaddr;
|
||||||
|
|
||||||
return sections.empty() ? 0 : sections.front()->getAddr();
|
return sections.empty() ? 0 : sections.front()->getAddr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -376,7 +376,7 @@ void set_relative_reloc(Elf_Rela *rel, Elf *elf, unsigned int value) {
|
||||||
rel->r_addend = value;
|
rel->r_addend = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void maybe_split_segment(Elf *elf, ElfSegment *segment)
|
void maybe_split_segment(Elf *elf, ElfSegment *segment, bool fill)
|
||||||
{
|
{
|
||||||
std::list<ElfSection *>::iterator it = segment->begin();
|
std::list<ElfSection *>::iterator it = segment->begin();
|
||||||
for (ElfSection *last = *(it++); it != segment->end(); last = *(it++)) {
|
for (ElfSection *last = *(it++); it != segment->end(); last = *(it++)) {
|
||||||
|
@ -396,19 +396,40 @@ void maybe_split_segment(Elf *elf, ElfSegment *segment)
|
||||||
phdr.p_memsz = (unsigned int)-1;
|
phdr.p_memsz = (unsigned int)-1;
|
||||||
ElfSegment *newSegment = new ElfSegment(&phdr);
|
ElfSegment *newSegment = new ElfSegment(&phdr);
|
||||||
elf->insertSegmentAfter(segment, newSegment);
|
elf->insertSegmentAfter(segment, newSegment);
|
||||||
|
ElfSection *section = *it;
|
||||||
for (; it != segment->end(); ++it) {
|
for (; it != segment->end(); ++it) {
|
||||||
newSegment->addSection(*it);
|
newSegment->addSection(*it);
|
||||||
}
|
}
|
||||||
for (it = newSegment->begin(); it != newSegment->end(); it++) {
|
for (it = newSegment->begin(); it != newSegment->end(); it++) {
|
||||||
segment->removeSection(*it);
|
segment->removeSection(*it);
|
||||||
}
|
}
|
||||||
|
// Fill the virtual address space gap left between the two PT_LOADs
|
||||||
|
// with a new PT_LOAD with no permissions. This avoids the linker
|
||||||
|
// (especially bionic's) filling the gap with anonymous memory,
|
||||||
|
// which breakpad doesn't like.
|
||||||
|
// /!\ running strip on a elfhacked binary will break this filler
|
||||||
|
// PT_LOAD.
|
||||||
|
if (!fill)
|
||||||
|
break;
|
||||||
|
ElfSection *previous = section->getPrevious();
|
||||||
|
phdr.p_vaddr = (previous->getAddr() + previous->getSize() + segment->getAlign() - 1) & ~(segment->getAlign() - 1);
|
||||||
|
phdr.p_paddr = phdr.p_vaddr + segment->getVPDiff();
|
||||||
|
phdr.p_flags = 0;
|
||||||
|
phdr.p_align = 0;
|
||||||
|
phdr.p_filesz = (section->getAddr() & ~(newSegment->getAlign() - 1)) - phdr.p_vaddr;
|
||||||
|
phdr.p_memsz = phdr.p_filesz;
|
||||||
|
if (phdr.p_filesz) {
|
||||||
|
newSegment = new ElfSegment(&phdr);
|
||||||
|
assert(newSegment->isElfHackFillerSegment());
|
||||||
|
elf->insertSegmentAfter(segment, newSegment);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Rel_Type>
|
template <typename Rel_Type>
|
||||||
int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type2, bool force)
|
int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type2, bool force, bool fill)
|
||||||
{
|
{
|
||||||
ElfDynamic_Section *dyn = elf->getDynSection();
|
ElfDynamic_Section *dyn = elf->getDynSection();
|
||||||
if (dyn ==NULL) {
|
if (dyn ==NULL) {
|
||||||
|
@ -568,7 +589,7 @@ int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type
|
||||||
// Adjust PT_LOAD segments
|
// Adjust PT_LOAD segments
|
||||||
for (ElfSegment *segment = elf->getSegmentByType(PT_LOAD); segment;
|
for (ElfSegment *segment = elf->getSegmentByType(PT_LOAD); segment;
|
||||||
segment = elf->getSegmentByType(PT_LOAD, segment)) {
|
segment = elf->getSegmentByType(PT_LOAD, segment)) {
|
||||||
maybe_split_segment(elf, segment);
|
maybe_split_segment(elf, segment, fill);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure Elf sections will be at their final location.
|
// Ensure Elf sections will be at their final location.
|
||||||
|
@ -599,7 +620,7 @@ static inline int backup_file(const char *name)
|
||||||
return rename(name, fname.c_str());
|
return rename(name, fname.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_file(const char *name, bool backup = false, bool force = false)
|
void do_file(const char *name, bool backup = false, bool force = false, bool fill = false)
|
||||||
{
|
{
|
||||||
std::ifstream file(name, std::ios::in|std::ios::binary);
|
std::ifstream file(name, std::ios::in|std::ios::binary);
|
||||||
Elf elf(file);
|
Elf elf(file);
|
||||||
|
@ -622,13 +643,13 @@ void do_file(const char *name, bool backup = false, bool force = false)
|
||||||
int exit = -1;
|
int exit = -1;
|
||||||
switch (elf.getMachine()) {
|
switch (elf.getMachine()) {
|
||||||
case EM_386:
|
case EM_386:
|
||||||
exit = do_relocation_section<Elf_Rel>(&elf, R_386_RELATIVE, R_386_32, force);
|
exit = do_relocation_section<Elf_Rel>(&elf, R_386_RELATIVE, R_386_32, force, fill);
|
||||||
break;
|
break;
|
||||||
case EM_X86_64:
|
case EM_X86_64:
|
||||||
exit = do_relocation_section<Elf_Rela>(&elf, R_X86_64_RELATIVE, R_X86_64_64, force);
|
exit = do_relocation_section<Elf_Rela>(&elf, R_X86_64_RELATIVE, R_X86_64_64, force, fill);
|
||||||
break;
|
break;
|
||||||
case EM_ARM:
|
case EM_ARM:
|
||||||
exit = do_relocation_section<Elf_Rel>(&elf, R_ARM_RELATIVE, R_ARM_ABS32, force);
|
exit = do_relocation_section<Elf_Rel>(&elf, R_ARM_RELATIVE, R_ARM_ABS32, force, fill);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (exit == 0) {
|
if (exit == 0) {
|
||||||
|
@ -677,8 +698,14 @@ void undo_file(const char *name, bool backup = false)
|
||||||
|
|
||||||
ElfSegment *first = elf.getSegmentByType(PT_LOAD);
|
ElfSegment *first = elf.getSegmentByType(PT_LOAD);
|
||||||
ElfSegment *second = elf.getSegmentByType(PT_LOAD, first);
|
ElfSegment *second = elf.getSegmentByType(PT_LOAD, first);
|
||||||
|
ElfSegment *filler = NULL;
|
||||||
|
// If the second PT_LOAD is a filler from elfhack --fill, check the third.
|
||||||
|
if (!second->isElfHackFillerSegment()) {
|
||||||
|
filler = second;
|
||||||
|
second = elf.getSegmentByType(PT_LOAD, filler);
|
||||||
|
}
|
||||||
if (second->getFlags() != first->getFlags()) {
|
if (second->getFlags() != first->getFlags()) {
|
||||||
fprintf(stderr, "First two PT_LOAD segments don't have the same flags. Skipping\n");
|
fprintf(stderr, "Couldn't identify elfhacked PT_LOAD segments. Skipping\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Move sections from the second PT_LOAD to the first, and remove the
|
// Move sections from the second PT_LOAD to the first, and remove the
|
||||||
|
@ -688,6 +715,8 @@ void undo_file(const char *name, bool backup = false)
|
||||||
first->addSection(*section);
|
first->addSection(*section);
|
||||||
|
|
||||||
elf.removeSegment(second);
|
elf.removeSegment(second);
|
||||||
|
if (filler)
|
||||||
|
elf.removeSegment(filler);
|
||||||
|
|
||||||
if (backup && backup_file(name) != 0) {
|
if (backup && backup_file(name) != 0) {
|
||||||
fprintf(stderr, "Couln't create backup file\n");
|
fprintf(stderr, "Couln't create backup file\n");
|
||||||
|
@ -704,6 +733,7 @@ int main(int argc, char *argv[])
|
||||||
bool backup = false;
|
bool backup = false;
|
||||||
bool force = false;
|
bool force = false;
|
||||||
bool revert = false;
|
bool revert = false;
|
||||||
|
bool fill = false;
|
||||||
char *lastSlash = rindex(argv[0], '/');
|
char *lastSlash = rindex(argv[0], '/');
|
||||||
if (lastSlash != NULL)
|
if (lastSlash != NULL)
|
||||||
rundir = strndup(argv[0], lastSlash - argv[0]);
|
rundir = strndup(argv[0], lastSlash - argv[0]);
|
||||||
|
@ -714,10 +744,12 @@ int main(int argc, char *argv[])
|
||||||
backup = true;
|
backup = true;
|
||||||
else if (strcmp(argv[arg], "-r") == 0)
|
else if (strcmp(argv[arg], "-r") == 0)
|
||||||
revert = true;
|
revert = true;
|
||||||
else if (revert)
|
else if (strcmp(argv[arg], "--fill") == 0)
|
||||||
|
fill = true;
|
||||||
|
else if (revert) {
|
||||||
undo_file(argv[arg], backup);
|
undo_file(argv[arg], backup);
|
||||||
else
|
} else
|
||||||
do_file(argv[arg], backup, force);
|
do_file(argv[arg], backup, force, fill);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(rundir);
|
free(rundir);
|
||||||
|
|
|
@ -460,6 +460,10 @@ public:
|
||||||
std::list<ElfSection *>::iterator end() { return sections.end(); }
|
std::list<ElfSection *>::iterator end() { return sections.end(); }
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
bool isElfHackFillerSegment() {
|
||||||
|
return type == PT_LOAD && flags == 0;
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
unsigned int type;
|
unsigned int type;
|
||||||
int v_p_diff; // Difference between physical and virtual address
|
int v_p_diff; // Difference between physical and virtual address
|
||||||
|
|
Загрузка…
Ссылка в новой задаче