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:
Mike Hommey 2013-01-02 10:17:32 +01:00
Родитель 987dc92252
Коммит d16fd4e0d9
3 изменённых файлов: 56 добавлений и 13 удалений

Просмотреть файл

@ -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