this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Implemented an __eh_frame reader & relocator to fix __eh_frame overruns when a terminating entry is missing. This implementation will enable future DWARF register code fixups on i386

+1050 -4
+4
src/dyld/CMakeLists.txt
··· 7 7 endif(COMMAND cmake_policy) 8 8 9 9 set(dyld_SRCS 10 + eh/DwarfPointer.cpp 11 + eh/BufWriter.cpp 12 + eh/BufReader.cpp 13 + eh/EHSection.cpp 10 14 FileMap.cpp 11 15 MachOLoader.cpp 12 16 Trampoline.cpp
+18 -4
src/dyld/MachOLoader.cpp
··· 40 40 #include <errno.h> 41 41 #include <dlfcn.h> 42 42 #include <libgen.h> 43 + #include "eh/EHSection.h" 43 44 44 45 FileMap g_file_map; 45 46 static std::vector<std::string> g_bound_names; ··· 655 656 { 656 657 LOG << "Perform " << b.macho->binds().size() << " binds\n"; 657 658 doBind(b.macho->binds(), b.slide, b.bindLazy); 658 - if (b.macho->get_eh_frame().first) 659 + 660 + auto eh_frame = b.macho->get_eh_frame(); 661 + if (eh_frame.first) 659 662 { 660 - void* frame = reinterpret_cast<void*>(b.macho->get_eh_frame().first + b.slide); 661 - LOG << "Registering EH frame at " << frame << std::endl; 662 - __register_frame(frame); 663 + EHSection ehSection; 664 + void* eh_data; 665 + uintptr_t bytes; 666 + void* eh_frame_ptr; 667 + 668 + eh_frame_ptr = (void*) (eh_frame.first + b.slide); 669 + LOG << "Reworking __eh_frame at " << eh_frame_ptr << std::endl; 670 + 671 + ehSection.load(eh_frame_ptr, eh_frame.second); 672 + ehSection.store(&eh_data, &bytes); 673 + 674 + LOG << "Registering reworked __eh_frame at " << eh_data << std::endl; 675 + __register_frame(eh_data); // TODO: free when unloading the image 663 676 } 677 + 664 678 for (LoaderHookFunc* func : g_machoLoaderHooks) 665 679 func(b.header, b.slide); 666 680 }
+142
src/dyld/eh/BufReader.cpp
··· 1 + /* 2 + This file is part of Darling. 3 + 4 + Copyright (C) 2013 Lubos Dolezel 5 + 6 + Darling is free software: you can redistribute it and/or modify 7 + it under the terms of the GNU General Public License as published by 8 + the Free Software Foundation, either version 3 of the License, or 9 + (at your option) any later version. 10 + 11 + Darling is distributed in the hope that it will be useful, 12 + but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + GNU General Public License for more details. 15 + 16 + You should have received a copy of the GNU General Public License 17 + along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #include "BufReader.h" 21 + #include <stdexcept> 22 + 23 + BufReader::BufReader(const void* mem, uintptr_t length) 24 + { 25 + m_pPos = m_pStart = static_cast<const char*>(mem); 26 + m_pEnd = m_pStart + length; 27 + } 28 + 29 + void BufReader::checkRead(size_t bytes) const 30 + { 31 + if (m_pPos+bytes > m_pEnd) 32 + throw std::runtime_error("Read beyond buffer's end"); 33 + } 34 + 35 + const void* BufReader::readBlock(size_t bytes) 36 + { 37 + const char* rv = m_pPos; 38 + 39 + checkRead(bytes); 40 + m_pPos += bytes; 41 + 42 + return rv; 43 + } 44 + 45 + const char* BufReader::readString() 46 + { 47 + const char* start = m_pPos; 48 + 49 + while (read()); 50 + 51 + return start; 52 + } 53 + 54 + void BufReader::unget(size_t bytes) 55 + { 56 + if (m_pPos - bytes < m_pStart) 57 + throw std::runtime_error("Unget beyond buffer's start"); 58 + m_pPos -= bytes; 59 + } 60 + 61 + uint64_t BufReader::readULEB128() 62 + { 63 + uint64_t r = 0; 64 + int s = 0; 65 + uint8_t val; 66 + 67 + do 68 + { 69 + val = read(); 70 + r |= (uint64_t)(val & 0x7f) << s; 71 + s += 7; 72 + } 73 + while (val & 0x80); 74 + 75 + return r; 76 + } 77 + 78 + int64_t BufReader::readLEB128() 79 + { 80 + int64_t r = 0; 81 + int s = 0; 82 + for (;;) 83 + { 84 + uint8_t b = read(); 85 + if (b < 0x80) 86 + { 87 + if (b & 0x40) 88 + r -= (0x80 - b) << s; 89 + else 90 + r |= (b & 0x3f) << s; 91 + break; 92 + } 93 + r |= (b & 0x7f) << s; 94 + s += 7; 95 + } 96 + return r; 97 + } 98 + 99 + DwarfPointer BufReader::readDwarfPointer(uint8_t encoding) 100 + { 101 + DwarfPointer ptr; 102 + 103 + ptr.encoding = encoding; 104 + ptr.originalLocation = pos(); 105 + 106 + switch (encoding & 0x0f) 107 + { 108 + case 0x01: // uleb128 109 + ptr.udata8 = readULEB128(); 110 + break; 111 + case 0x02: // udata2 112 + ptr.udata2 = read16(); 113 + break; 114 + case 0x03: // udata4 115 + ptr.udata4 = read32(); 116 + break; 117 + case 0x04: // udata8 118 + ptr.udata8 = read64(); 119 + break; 120 + case (0x01|0x08): // sleb128 121 + ptr.sdata8 = readLEB128(); 122 + break; 123 + case (0x02|0x08): // sdata2 124 + ptr.sdata2 = read16S(); 125 + break; 126 + case (0x03|0x08): // sdata4 127 + ptr.sdata4 = read32S(); 128 + break; 129 + case (0x04|0x08): // sdata8 130 + ptr.sdata8 = read64S(); 131 + break; 132 + case 0: // absptr 133 + { 134 + if (sizeof(void*) == 4) 135 + ptr.udata4 = read32(); 136 + else 137 + ptr.udata8 = read64(); 138 + } 139 + } 140 + 141 + return ptr; 142 + }
+68
src/dyld/eh/BufReader.h
··· 1 + /* 2 + This file is part of Darling. 3 + 4 + Copyright (C) 2013 Lubos Dolezel 5 + 6 + Darling is free software: you can redistribute it and/or modify 7 + it under the terms of the GNU General Public License as published by 8 + the Free Software Foundation, either version 3 of the License, or 9 + (at your option) any later version. 10 + 11 + Darling is distributed in the hope that it will be useful, 12 + but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + GNU General Public License for more details. 15 + 16 + You should have received a copy of the GNU General Public License 17 + along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #ifndef BUFREADER_H 21 + #define BUFREADER_H 22 + #include <stdint.h> 23 + #include <stddef.h> 24 + #include "DwarfPointer.h" 25 + 26 + 27 + class BufReader 28 + { 29 + public: 30 + BufReader(const void* mem, uintptr_t length); 31 + 32 + template<typename T> T readType() { const T* t = static_cast<const T*>(readBlock(sizeof(T))); return *t; } 33 + 34 + uintptr_t readPtr() { return readType<uintptr_t>(); } 35 + intptr_t readPtrS() { return readType<intptr_t>(); } 36 + 37 + uint16_t read16() { return readType<uint16_t>(); } 38 + int16_t read16S() { return readType<int16_t>(); } 39 + 40 + uint32_t read32() { return readType<uint32_t>(); } 41 + int32_t read32S() { return readType<int32_t>(); } 42 + 43 + uint64_t read64() { return readType<uint64_t>(); } 44 + int64_t read64S() { return readType<int64_t>(); } 45 + 46 + uint8_t read() { return readType<uint8_t>(); } 47 + int8_t readS() { return readType<int8_t>(); } 48 + 49 + uint64_t readULEB128(); 50 + int64_t readLEB128(); 51 + 52 + DwarfPointer readDwarfPointer(uint8_t encoding); 53 + 54 + const void* readBlock(size_t bytes); 55 + const char* readString(); 56 + 57 + void unget(size_t bytes); 58 + 59 + bool atEnd() const { return m_pPos == m_pEnd; } 60 + uintptr_t pos() const { return reinterpret_cast<uintptr_t>(m_pPos); } 61 + void moveTo(uintptr_t pos) { m_pPos = reinterpret_cast<const char*>(pos); } 62 + private: 63 + void checkRead(size_t bytes) const; 64 + private: 65 + const char *m_pStart, *m_pPos, *m_pEnd; 66 + }; 67 + 68 + #endif
+125
src/dyld/eh/BufWriter.cpp
··· 1 + /* 2 + This file is part of Darling. 3 + 4 + Copyright (C) 2013 Lubos Dolezel 5 + 6 + Darling is free software: you can redistribute it and/or modify 7 + it under the terms of the GNU General Public License as published by 8 + the Free Software Foundation, either version 3 of the License, or 9 + (at your option) any later version. 10 + 11 + Darling is distributed in the hope that it will be useful, 12 + but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + GNU General Public License for more details. 15 + 16 + You should have received a copy of the GNU General Public License 17 + along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #include "BufWriter.h" 21 + #include <stdexcept> 22 + #include <cstring> 23 + 24 + BufWriter::BufWriter(void* mem, uintptr_t length) 25 + { 26 + m_pPos = m_pStart = static_cast<char*>(mem); 27 + m_pEnd = m_pStart + length; 28 + } 29 + 30 + void BufWriter::writeULEB128(uint64_t v) 31 + { 32 + do 33 + { 34 + uint8_t byte = v & 0x7f; 35 + v >>= 7; 36 + if (v != 0) 37 + byte |= 0x80; 38 + write(byte); 39 + } 40 + while (v != 0); 41 + } 42 + 43 + void BufWriter::writeLEB128(int64_t v) 44 + { 45 + bool more = true; 46 + bool negative = (v < 0); 47 + 48 + int bitsUsed = 0; 49 + for (int i = 0; i < 64; i++) 50 + { 51 + if (v & (1ll << i)) 52 + bitsUsed = i+1; 53 + } 54 + 55 + while(more) 56 + { 57 + uint8_t byte = v & 0x7f; 58 + v >>= 7; 59 + 60 + if (negative) 61 + v |= - (1 <<(bitsUsed - 7)); 62 + 63 + if ((v == 0 && !(byte & 0x40)) || (v == -1 && (byte & 0x40))) 64 + more = false; 65 + else 66 + byte |= 0x80; 67 + write(byte); 68 + } 69 + } 70 + 71 + void BufWriter::writeDwarfPointer(DwarfPointer ptr) 72 + { 73 + switch (ptr.encoding & 0xf) 74 + { 75 + case 0x01: // uleb128 76 + writeULEB128(ptr.udata8); 77 + break; 78 + case 0x02: // udata2 79 + write16(ptr.udata2); 80 + break; 81 + case 0x03: // udata4 82 + write32(ptr.udata4); 83 + break; 84 + case 0x04: // udata8 85 + write64(ptr.udata8); 86 + break; 87 + case (0x01|0x08): // sleb128 88 + writeLEB128(ptr.sdata8); 89 + break; 90 + case (0x02|0x08): // sdata2 91 + write16S(ptr.sdata2); 92 + break; 93 + case (0x03|0x08): // sdata4 94 + write32S(ptr.sdata4); 95 + break; 96 + case (0x04|0x08): // sdata8 97 + write64S(ptr.sdata8); 98 + break; 99 + case 0: // absptr 100 + { 101 + if (sizeof(void*) == 4) 102 + write32(ptr.udata4); 103 + else 104 + write64(ptr.udata8); 105 + } 106 + } 107 + } 108 + 109 + void BufWriter::writeBlock(const void* p, size_t bytes) 110 + { 111 + checkWrite(bytes); 112 + memcpy(m_pPos, p, bytes); 113 + m_pPos += bytes; 114 + } 115 + 116 + void BufWriter::writeString(const char* str) 117 + { 118 + writeBlock(str, strlen(str)+1); 119 + } 120 + 121 + void BufWriter::checkWrite(size_t bytes) const 122 + { 123 + if (m_pPos+bytes > m_pEnd) 124 + throw std::runtime_error("Write beyond buffer's end"); 125 + }
+67
src/dyld/eh/BufWriter.h
··· 1 + /* 2 + This file is part of Darling. 3 + 4 + Copyright (C) 2013 Lubos Dolezel 5 + 6 + Darling is free software: you can redistribute it and/or modify 7 + it under the terms of the GNU General Public License as published by 8 + the Free Software Foundation, either version 3 of the License, or 9 + (at your option) any later version. 10 + 11 + Darling is distributed in the hope that it will be useful, 12 + but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + GNU General Public License for more details. 15 + 16 + You should have received a copy of the GNU General Public License 17 + along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #ifndef BUFWRITER_H 21 + #define BUFWRITER_H 22 + #include <stdint.h> 23 + #include <stddef.h> 24 + #include "DwarfPointer.h" 25 + 26 + class BufWriter 27 + { 28 + public: 29 + BufWriter(void* mem, uintptr_t length); 30 + 31 + template<typename T> void writeType(T t) { writeBlock(&t, sizeof(T)); } 32 + 33 + void writePtr(uintptr_t v) { return writeType<uintptr_t>(v); } 34 + void writePtrS(intptr_t v) { return writeType<intptr_t>(v); } 35 + 36 + void write16(uint16_t v) { return writeType<uint16_t>(v); } 37 + void write16S(int16_t v) { return writeType<int16_t>(v); } 38 + 39 + void write32(uint32_t v) { return writeType<uint32_t>(v); } 40 + void write32S(int32_t v) { return writeType<int32_t>(v); } 41 + 42 + void write64(uint64_t v) { return writeType<uint64_t>(v); } 43 + void write64S(int64_t v) { return writeType<int64_t>(v); } 44 + 45 + void write(uint8_t v) { return writeType<uint8_t>(v); } 46 + void writeS(int8_t v) { return writeType<int8_t>(v); } 47 + 48 + void writeULEB128(uint64_t v); 49 + void writeLEB128(int64_t v); 50 + 51 + void writeDwarfPointer(DwarfPointer ptr); 52 + 53 + void writeBlock(const void* p, size_t bytes); 54 + void writeString(const char* str); 55 + 56 + bool atEnd() const { return m_pPos == m_pEnd; } 57 + uintptr_t pos() const { return reinterpret_cast<uintptr_t>(m_pPos); } 58 + uintptr_t relativePos() const { return m_pPos - m_pStart; } 59 + char* posPtr() const { return m_pPos; } 60 + void moveTo(uintptr_t pos) { m_pPos = reinterpret_cast<char*>(pos); } 61 + private: 62 + void checkWrite(size_t bytes) const; 63 + private: 64 + char *m_pStart, *m_pPos, *m_pEnd; 65 + }; 66 + 67 + #endif
+101
src/dyld/eh/DwarfPointer.cpp
··· 1 + #include "DwarfPointer.h" 2 + #include <stdexcept> 3 + 4 + bool DwarfPointer::relocateToAddr(uintptr_t addr, uintptr_t originalBlockStart, uintptr_t originalBlockEnd) 5 + { 6 + if (!(encoding & 0x10)) // DW_EH_PE_pcrel; == cannot be used because pcrel can be combined with indirect... 7 + return false; 8 + 9 + if (originalLocation+getSigned() >= originalBlockStart && originalLocation+getSigned() < originalBlockEnd) 10 + return false; // nothing to change, it was inside of the EH block 11 + 12 + setSigned(getSigned() + (originalLocation - addr)); 13 + originalLocation = addr; 14 + return true; 15 + } 16 + 17 + int DwarfPointer::getSize() 18 + { 19 + return getSize(encoding); 20 + } 21 + 22 + int DwarfPointer::getSize(uint8_t encoding) 23 + { 24 + switch (encoding & 0xf) 25 + { 26 + case 0x01: // uleb128 27 + throw std::logic_error("leb128 size cannot be precalculated"); 28 + case 0x02: // udata2 29 + return 2; 30 + case 0x03: // udata4 31 + return 4; 32 + case 0x04: // udata8 33 + return 8; 34 + case (0x01|0x08): // sleb128 35 + throw std::logic_error("uleb128 size cannot be precalculated"); 36 + case (0x02|0x08): // sdata2 37 + return 2; 38 + case (0x03|0x08): // sdata4 39 + return 4; 40 + case (0x04|0x08): // sdata8 41 + return 8; 42 + case 0: // absptr 43 + return sizeof(void*); 44 + } 45 + return 0; 46 + } 47 + 48 + int64_t DwarfPointer::getSigned() 49 + { 50 + switch (encoding & 0xf) 51 + { 52 + case 0x01: // uleb128 53 + return udata8; 54 + case 0x02: // udata2 55 + return udata2; 56 + case 0x03: // udata4 57 + return udata4; 58 + case 0x04: // udata8 59 + return udata8; 60 + case (0x01|0x08): // sleb128 61 + return sdata8; 62 + case (0x02|0x08): // sdata2 63 + return sdata2; 64 + case (0x03|0x08): // sdata4 65 + return sdata4; 66 + case (0x04|0x08): // sdata8 67 + return sdata8; 68 + case 0: // absptr 69 + { 70 + if (sizeof(void*) == 4) 71 + return udata4; 72 + else 73 + return udata8; 74 + } 75 + } 76 + return 0; // to shut the compiler up 77 + } 78 + 79 + void DwarfPointer::setSigned(intptr_t value) 80 + { 81 + uint8_t newEncoding = encoding & 0xf0; 82 + 83 + // always use sdata4/8 to simplify calculations in EHSection 84 + if (sizeof(void*) == 8) 85 + { 86 + newEncoding |= (0x04|0x08); 87 + sdata8 = value; 88 + } 89 + else 90 + { 91 + newEncoding |= (0x03|0x08); 92 + sdata4 = value; 93 + } 94 + encoding = newEncoding; 95 + } 96 + 97 + void DwarfPointer::prepareForRelocation() 98 + { 99 + if (encoding != 0xff) // DW_EH_PE_omit 100 + setSigned(getSigned()); 101 + }
+52
src/dyld/eh/DwarfPointer.h
··· 1 + /* 2 + This file is part of Darling. 3 + 4 + Copyright (C) 2013 Lubos Dolezel 5 + 6 + Darling is free software: you can redistribute it and/or modify 7 + it under the terms of the GNU General Public License as published by 8 + the Free Software Foundation, either version 3 of the License, or 9 + (at your option) any later version. 10 + 11 + Darling is distributed in the hope that it will be useful, 12 + but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + GNU General Public License for more details. 15 + 16 + You should have received a copy of the GNU General Public License 17 + along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #ifndef DWARFPOINTER_H 21 + #define DWARFPOINTER_H 22 + #include <stdint.h> 23 + 24 + struct DwarfPointer 25 + { 26 + DwarfPointer() : encoding(0xff), sdata8(0) {} 27 + 28 + bool relocateToAddr(uintptr_t addr, uintptr_t originalBlockStart, uintptr_t originalBlockEnd); 29 + int64_t getSigned(); 30 + void setSigned(intptr_t value); 31 + 32 + // Used to change the internal data type to what is used after relocation 33 + // Needed when we need to write the encoding somewhere (CIE) long before writing the pointer itself (FDE) 34 + void prepareForRelocation(); 35 + int getSize(); 36 + static int getSize(uint8_t encoding); 37 + 38 + uint8_t encoding; 39 + union 40 + { 41 + uint64_t udata8; 42 + int64_t sdata8; 43 + uint32_t udata4; 44 + int32_t sdata4; 45 + uint16_t udata2; 46 + int32_t sdata2; 47 + }; 48 + 49 + uintptr_t originalLocation; 50 + }; 51 + 52 + #endif
+376
src/dyld/eh/EHSection.cpp
··· 1 + /* 2 + This file is part of Darling. 3 + 4 + Copyright (C) 2013 Lubos Dolezel 5 + 6 + Darling is free software: you can redistribute it and/or modify 7 + it under the terms of the GNU General Public License as published by 8 + the Free Software Foundation, either version 3 of the License, or 9 + (at your option) any later version. 10 + 11 + Darling is distributed in the hope that it will be useful, 12 + but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + GNU General Public License for more details. 15 + 16 + You should have received a copy of the GNU General Public License 17 + along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #include "EHSection.h" 21 + #include <string> 22 + #include <stdexcept> 23 + #include <sstream> 24 + #include <limits> 25 + #include <memory> 26 + #include <cstring> 27 + #include "../../util/log.h" 28 + 29 + EHSection::EHSection() 30 + { 31 + } 32 + 33 + EHSection::~EHSection() 34 + { 35 + clear(); 36 + } 37 + 38 + void EHSection::clear() 39 + { 40 + for (CIE* cie : m_cies) 41 + { 42 + for (FDE* fde : cie->fdes) 43 + delete fde; 44 + delete cie; 45 + } 46 + m_cies.clear(); 47 + m_ciePositions.clear(); 48 + } 49 + 50 + 51 + void EHSection::load(const void* start, uintptr_t length) 52 + { 53 + BufReader reader(start, length); 54 + 55 + clear(); 56 + 57 + m_originalStart = reinterpret_cast<uintptr_t>(start); 58 + m_originalEnd = m_originalStart + length; 59 + 60 + while (!reader.atEnd()) 61 + { 62 + uint64_t length; 63 + int32_t id; 64 + uintptr_t location, endPos; 65 + 66 + location = reader.pos(); 67 + 68 + length = uint64_t(reader.read32()) & 0xffffffff; 69 + 70 + if (length == 0xffffffff) 71 + length = reader.read64(); 72 + else if (!length) 73 + break; // terminating entry 74 + 75 + endPos = reader.pos() + length; 76 + id = reader.read32S(); 77 + 78 + if (!id) 79 + loadCIE(reader, endPos, location); 80 + else 81 + { 82 + uintptr_t pos = reader.pos() - sizeof(id); // offset is from the id field 83 + pos -= id; 84 + 85 + auto it = m_ciePositions.find(pos); 86 + if (it == m_ciePositions.end()) 87 + { 88 + std::stringstream ss; 89 + ss << "CIE not found for position " << std::hex << pos << std::dec << std::endl; 90 + throw std::runtime_error(ss.str()); 91 + } 92 + 93 + loadFDE(reader, endPos, it->second); 94 + } 95 + } 96 + } 97 + 98 + void EHSection::loadCIE(BufReader& reader, uint64_t endPos, uintptr_t location) 99 + { 100 + CIE* cie = new CIE; 101 + 102 + cie->start = reader.pos(); 103 + cie->version = reader.read(); 104 + cie->augmentationString = reader.readString(); 105 + cie->codeAlign = reader.readLEB128(); 106 + cie->dataAlign = reader.readLEB128(); 107 + 108 + if (cie->codeAlign != 1) 109 + { 110 + std::stringstream ss; 111 + ss << "Invalid code alignment: " << int(cie->codeAlign) << std::endl; 112 + delete cie; 113 + throw std::runtime_error(ss.str()); 114 + } 115 + 116 + if (cie->version == 1) 117 + cie->returnRegister = reader.read(); 118 + else if (cie->version == 3) 119 + cie->returnRegister = reader.readLEB128(); 120 + else 121 + { 122 + std::stringstream ss; 123 + ss << "Invalid CIE version: " << int(cie->version) << std::endl; 124 + delete cie; 125 + throw std::runtime_error(ss.str()); 126 + } 127 + 128 + cie->augmentationDataPresent = false; 129 + 130 + uint64_t augmentationDataLength, augmentationDataEnd; 131 + 132 + cie->lsdaEncoding = cie->ptrEncoding = 0xff; 133 + 134 + for (const char* augP = cie->augmentationString; *augP; augP++) 135 + { 136 + switch (*augP) 137 + { 138 + case 'z': 139 + cie->augmentationDataPresent = true; 140 + augmentationDataLength = reader.readULEB128(); 141 + augmentationDataEnd = reader.pos() + augmentationDataLength; 142 + break; 143 + case 'L': 144 + cie->lsdaEncoding = reader.read(); 145 + break; 146 + case 'R': 147 + cie->ptrEncoding = reader.read(); 148 + break; 149 + case 'P': 150 + { 151 + uint8_t persEncoding = reader.read(); 152 + cie->personality = reader.readDwarfPointer(persEncoding); 153 + break; 154 + } 155 + case 'S': 156 + break; 157 + default: 158 + { 159 + std::stringstream ss; 160 + ss << "Unsupported character in CIE augmentation string: " << *augP; 161 + delete cie; 162 + 163 + throw std::runtime_error(ss.str()); 164 + } 165 + } 166 + } 167 + 168 + reader.moveTo(augmentationDataEnd); 169 + 170 + uint64_t instructionsLength = endPos - reader.pos(); 171 + const uint8_t* data = reinterpret_cast<const uint8_t*>(reader.readBlock(instructionsLength)); 172 + 173 + cie->instructions.assign(data, data+instructionsLength); 174 + 175 + m_cies.push_back(cie); 176 + m_ciePositions[location] = cie; 177 + 178 + LOG << "Loaded a CIE at " << std::hex << location << std::dec << std::endl; 179 + } 180 + 181 + void EHSection::loadFDE(BufReader& reader, uint64_t endPos, CIE* cie) 182 + { 183 + FDE* fde = new FDE; 184 + 185 + fde->startAddress = reader.readDwarfPointer(cie->ptrEncoding); 186 + fde->length = reader.readDwarfPointer(cie->ptrEncoding); // if ptrEncoding is relative, then in context of length, it is still just a plain number 187 + 188 + if (*cie->augmentationString == 'z') 189 + { 190 + fde->augmentationDataLength = reader.readLEB128(); 191 + //fde->augmentationData = reinterpret_cast<const uint8_t*>(reader.readBlock(fde->augmentationDataLength)); 192 + } 193 + else 194 + { 195 + fde->augmentationDataLength = 0; 196 + //fde->augmentationData = nullptr; 197 + } 198 + 199 + if (strchr(cie->augmentationString, 'L') && cie->lsdaEncoding != 0xff) // DW_EH_PE_omit 200 + fde->lsdaPointer = reader.readDwarfPointer(cie->lsdaEncoding); 201 + 202 + uint64_t instructionsLength = endPos - reader.pos(); 203 + const uint8_t* data = reinterpret_cast<const uint8_t*>(reader.readBlock(instructionsLength)); 204 + 205 + fde->instructions.assign(data, data+instructionsLength); 206 + 207 + cie->fdes.push_back(fde); 208 + } 209 + 210 + void EHSection::store(void** mem, uintptr_t* length) 211 + { 212 + uintptr_t originalLength = m_originalEnd - m_originalStart; 213 + uintptr_t newLength; 214 + 215 + // We're being pessimistic here, but we cannot use a resizable buffer, 216 + // since a possible move doing realloc() would invalidate the relative pointers 217 + newLength = originalLength * 2; 218 + 219 + *mem = new char[newLength]; 220 + 221 + BufWriter writer (*mem, newLength); 222 + 223 + for (CIE* cie : m_cies) 224 + { 225 + uintptr_t cieStart = writer.pos(); 226 + // Write the CIE 227 + storeCIE(writer, cie); 228 + 229 + // Write all the FDEs contained 230 + for (FDE* fde : cie->fdes) 231 + storeFDE(writer, fde, cie, cieStart); 232 + } 233 + 234 + // terminating entry 235 + writer.write32(0); 236 + 237 + *length = writer.pos() - reinterpret_cast<uintptr_t>(*mem); 238 + } 239 + 240 + void EHSection::storeCIE(BufWriter& writer, CIE* cie) 241 + { 242 + uint32_t* totalLength32 = nullptr; 243 + uint64_t* totalLength64 = nullptr; 244 + 245 + if (cie->instructions.size() < std::numeric_limits<uint32_t>::max() - 100) // approximation 246 + { 247 + totalLength32 = reinterpret_cast<uint32_t*>(writer.posPtr()); 248 + writer.write32(0); // we fill this up later 249 + } 250 + else 251 + { 252 + writer.write32(0xffffffff); 253 + totalLength64 = reinterpret_cast<uint64_t*>(writer.posPtr()); 254 + writer.write64(0); // we fill this up later 255 + } 256 + 257 + uintptr_t startPos = writer.pos(); 258 + 259 + writer.write32(0); // id is always zero for a CIE 260 + 261 + writer.write(cie->version); 262 + writer.writeString(cie->augmentationString); 263 + writer.writeLEB128(cie->codeAlign); 264 + writer.writeLEB128(cie->dataAlign); 265 + 266 + if (cie->version == 1) 267 + writer.write(cie->returnRegister & 0xff); 268 + else if (cie->version == 3) 269 + writer.writeLEB128(cie->returnRegister); 270 + else 271 + throw std::runtime_error("Invalid CIE version"); 272 + 273 + // TODO: cie->lsdaEncodingPtr 274 + // augmentation data length will always be 275 + // 1 + 1 + 1 + 4|8 276 + 277 + uint64_t augLength = 0; 278 + if (strchr(cie->augmentationString, 'L')) 279 + augLength++; 280 + if (strchr(cie->augmentationString, 'R')) 281 + augLength++; 282 + if (strchr(cie->augmentationString, 'P')) 283 + augLength += sizeof(void*) + 1; // sizeof(void*), because relocateToAddr() forces this 284 + 285 + writer.writeULEB128(augLength); 286 + 287 + for (const char* augP = cie->augmentationString; *augP; augP++) 288 + { 289 + switch (*augP) 290 + { 291 + case 'z': 292 + break; 293 + case 'L': 294 + 295 + writer.write(cie->lsdaEncoding); 296 + break; 297 + case 'R': 298 + writer.write(cie->ptrEncoding); 299 + break; 300 + case 'P': 301 + { 302 + cie->personality.relocateToAddr(writer.pos()+1, m_originalStart, m_originalEnd); // not relocated?! 303 + writer.write(cie->personality.encoding); 304 + writer.writeDwarfPointer(cie->personality); 305 + break; 306 + } 307 + case 'S': 308 + break; 309 + default: 310 + { 311 + std::stringstream ss; 312 + ss << "Unsupported character in CIE augmentation string: " << *augP; 313 + delete cie; 314 + 315 + throw std::runtime_error(ss.str()); 316 + } 317 + } 318 + } 319 + 320 + writer.writeBlock(&cie->instructions[0], cie->instructions.size()); 321 + 322 + if (totalLength32) 323 + *totalLength32 = uint32_t( writer.pos() - startPos ); 324 + else 325 + *totalLength64 = writer.pos() - startPos; 326 + } 327 + 328 + void EHSection::storeFDE(BufWriter& writer, FDE* fde, CIE* cie, uintptr_t cieStart) 329 + { 330 + uint32_t* totalLength32 = nullptr; 331 + uint64_t* totalLength64 = nullptr; 332 + 333 + if (fde->instructions.size() < std::numeric_limits<uint32_t>::max() - 100) // approximation 334 + { 335 + totalLength32 = reinterpret_cast<uint32_t*>(writer.posPtr()); 336 + writer.write32(0); // we fill this up later 337 + } 338 + else 339 + { 340 + writer.write32(0xffffffff); 341 + totalLength64 = reinterpret_cast<uint64_t*>(writer.posPtr()); 342 + writer.write64(0); // we fill this up later 343 + } 344 + 345 + uintptr_t startPos = writer.pos(); 346 + int32_t id = int32_t(writer.pos() - cieStart); 347 + writer.write32S(id); 348 + 349 + fde->startAddress.relocateToAddr(writer.pos(), m_originalStart, m_originalEnd); 350 + writer.writeDwarfPointer(fde->startAddress); 351 + writer.writeDwarfPointer(fde->length); // length cannot be relative 352 + 353 + if (*cie->augmentationString == 'z') 354 + { 355 + bool hasLSDAPtr = (strchr(cie->augmentationString, 'L') && cie->lsdaEncoding != 0xff); // DW_EH_PE_omit 356 + 357 + writer.writeLEB128(hasLSDAPtr ? DwarfPointer::getSize(cie->lsdaEncoding) : 0); 358 + 359 + if (hasLSDAPtr) 360 + { 361 + fde->lsdaPointer.relocateToAddr(writer.pos(), m_originalStart, m_originalEnd); 362 + writer.writeDwarfPointer(fde->lsdaPointer); 363 + } 364 + } 365 + 366 + writer.writeBlock(&fde->instructions[0], fde->instructions.size()); 367 + 368 + if (totalLength32) 369 + *totalLength32 = uint32_t( writer.pos() - startPos ); 370 + else 371 + *totalLength64 = writer.pos() - startPos; 372 + } 373 + 374 + void EHSection::swapRegisterNumbers(const std::vector<std::pair<int, int>>& swapList) 375 + { 376 + }
+97
src/dyld/eh/EHSection.h
··· 1 + /* 2 + This file is part of Darling. 3 + 4 + Copyright (C) 2013 Lubos Dolezel 5 + 6 + Darling is free software: you can redistribute it and/or modify 7 + it under the terms of the GNU General Public License as published by 8 + the Free Software Foundation, either version 3 of the License, or 9 + (at your option) any later version. 10 + 11 + Darling is distributed in the hope that it will be useful, 12 + but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + GNU General Public License for more details. 15 + 16 + You should have received a copy of the GNU General Public License 17 + along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #ifndef EHSECTION_H 21 + #define EHSECTION_H 22 + #include <stdint.h> 23 + #include <vector> 24 + #include <map> 25 + #include "BufReader.h" 26 + #include "BufWriter.h" 27 + 28 + class EHSection 29 + { 30 + public: 31 + EHSection(); 32 + ~EHSection(); 33 + 34 + // Loads an __eh_frame 35 + void load(const void* start, uintptr_t length); 36 + 37 + // Serializes a previously loaded __eh_frame, appends a terminating entry 38 + // The returned memory must not be moved 39 + void store(void** mem, uintptr_t* length); 40 + 41 + // Frees all the internal structures 42 + void clear(); 43 + 44 + void swapRegisterNumbers(const std::vector<std::pair<int, int>>& swapList); 45 + private: 46 + struct CIE; 47 + struct FDE; 48 + 49 + // Loads a CIE from the given reader 50 + // endPos: absolute address of the first byte after this CIE, used to get the instruction block length 51 + // location: absolute address of the length field preceding this CIE 52 + void loadCIE(BufReader& reader, uint64_t endPos, uintptr_t location); 53 + 54 + // Loads an FDE from the given reader 55 + // endPos: absolute address of the first byte after this FDE, used to get the instruction block length 56 + // cie: a CIE this FDE is part of, determined by the location passed in loadCIE() matched by the 'id' 57 + void loadFDE(BufReader& reader, uint64_t endPos, CIE* cie); 58 + 59 + void storeCIE(BufWriter& writer, CIE* cie); 60 + void storeFDE(BufWriter& writer, FDE* fde, CIE* cie, uintptr_t cieStart); 61 + private: 62 + // Needed for relative pointer adjustments 63 + uintptr_t m_originalStart, m_originalEnd; 64 + 65 + struct FDE 66 + { 67 + DwarfPointer startAddress, length; 68 + const uint8_t* augmentationData; 69 + int64_t augmentationDataLength; 70 + DwarfPointer lsdaPointer; 71 + 72 + std::vector<uint8_t> instructions; 73 + }; 74 + 75 + struct CIE 76 + { 77 + uintptr_t start; 78 + uint8_t version; 79 + const char* augmentationString; 80 + int64_t codeAlign, dataAlign; 81 + int64_t returnRegister; 82 + bool augmentationDataPresent; 83 + uint8_t lsdaEncoding, ptrEncoding; 84 + DwarfPointer personality; 85 + 86 + std::vector<uint8_t> instructions; 87 + std::vector<FDE*> fdes; 88 + uint8_t* lsdaEncodingPtr; // only used when writing 89 + }; 90 + 91 + std::vector<CIE*> m_cies; 92 + 93 + // Used to look up the CIE an FDE belongs into 94 + std::map<uintptr_t, CIE*> m_ciePositions; 95 + }; 96 + 97 + #endif