зеркало из 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()
|
||||
{
|
||||
if (type == PT_GNU_RELRO)
|
||||
if (type == PT_GNU_RELRO || isElfHackFillerSegment())
|
||||
return filesz;
|
||||
|
||||
if (sections.empty())
|
||||
|
@ -604,7 +604,7 @@ unsigned int ElfSegment::getFileSize()
|
|||
|
||||
unsigned int ElfSegment::getMemSize()
|
||||
{
|
||||
if (type == PT_GNU_RELRO)
|
||||
if (type == PT_GNU_RELRO || isElfHackFillerSegment())
|
||||
return memsz;
|
||||
|
||||
if (sections.empty())
|
||||
|
@ -621,6 +621,10 @@ unsigned int ElfSegment::getOffset()
|
|||
(sections.front()->getAddr() != vaddr))
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -630,6 +634,9 @@ unsigned int ElfSegment::getAddr()
|
|||
(sections.front()->getAddr() != vaddr))
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -376,7 +376,7 @@ void set_relative_reloc(Elf_Rela *rel, Elf *elf, unsigned int 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();
|
||||
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;
|
||||
ElfSegment *newSegment = new ElfSegment(&phdr);
|
||||
elf->insertSegmentAfter(segment, newSegment);
|
||||
ElfSection *section = *it;
|
||||
for (; it != segment->end(); ++it) {
|
||||
newSegment->addSection(*it);
|
||||
}
|
||||
for (it = newSegment->begin(); it != newSegment->end(); 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
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
|
||||
for (ElfSegment *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.
|
||||
|
@ -599,7 +620,7 @@ static inline int backup_file(const char *name)
|
|||
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);
|
||||
Elf elf(file);
|
||||
|
@ -622,13 +643,13 @@ void do_file(const char *name, bool backup = false, bool force = false)
|
|||
int exit = -1;
|
||||
switch (elf.getMachine()) {
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
if (exit == 0) {
|
||||
|
@ -677,8 +698,14 @@ void undo_file(const char *name, bool backup = false)
|
|||
|
||||
ElfSegment *first = elf.getSegmentByType(PT_LOAD);
|
||||
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()) {
|
||||
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;
|
||||
}
|
||||
// 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);
|
||||
|
||||
elf.removeSegment(second);
|
||||
if (filler)
|
||||
elf.removeSegment(filler);
|
||||
|
||||
if (backup && backup_file(name) != 0) {
|
||||
fprintf(stderr, "Couln't create backup file\n");
|
||||
|
@ -704,6 +733,7 @@ int main(int argc, char *argv[])
|
|||
bool backup = false;
|
||||
bool force = false;
|
||||
bool revert = false;
|
||||
bool fill = false;
|
||||
char *lastSlash = rindex(argv[0], '/');
|
||||
if (lastSlash != NULL)
|
||||
rundir = strndup(argv[0], lastSlash - argv[0]);
|
||||
|
@ -714,10 +744,12 @@ int main(int argc, char *argv[])
|
|||
backup = true;
|
||||
else if (strcmp(argv[arg], "-r") == 0)
|
||||
revert = true;
|
||||
else if (revert)
|
||||
else if (strcmp(argv[arg], "--fill") == 0)
|
||||
fill = true;
|
||||
else if (revert) {
|
||||
undo_file(argv[arg], backup);
|
||||
else
|
||||
do_file(argv[arg], backup, force);
|
||||
} else
|
||||
do_file(argv[arg], backup, force, fill);
|
||||
}
|
||||
|
||||
free(rundir);
|
||||
|
|
|
@ -460,6 +460,10 @@ public:
|
|||
std::list<ElfSection *>::iterator end() { return sections.end(); }
|
||||
|
||||
void clear();
|
||||
|
||||
bool isElfHackFillerSegment() {
|
||||
return type == PT_LOAD && flags == 0;
|
||||
}
|
||||
private:
|
||||
unsigned int type;
|
||||
int v_p_diff; // Difference between physical and virtual address
|
||||
|
|
Загрузка…
Ссылка в новой задаче