1 //===- EhFrameReader.cpp --------------------------------------------------===// 2 // 3 // The MCLinker Project 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 #include <mcld/LD/EhFrameReader.h> 10 11 #include <llvm/ADT/StringRef.h> 12 #include <llvm/Support/Dwarf.h> 13 14 #include <mcld/MC/MCLDInput.h> 15 #include <mcld/LD/EhFrame.h> 16 #include <mcld/LD/LDSection.h> 17 #include <mcld/Support/MemoryArea.h> 18 #include <mcld/Support/MsgHandling.h> 19 20 using namespace mcld; 21 using namespace llvm::dwarf; 22 23 //===----------------------------------------------------------------------===// 24 // Helper Functions 25 //===----------------------------------------------------------------------===// 26 /// skip_LEB128 - skip the first LEB128 encoded value from *pp, update *pp 27 /// to the next character. 28 /// @return - false if we ran off the end of the string. 29 /// @ref - GNU gold 1.11, ehframe.h, Eh_frame::skip_leb128. 30 static bool 31 skip_LEB128(EhFrameReader::ConstAddress* pp, EhFrameReader::ConstAddress pend) 32 { 33 for (EhFrameReader::ConstAddress p = *pp; p < pend; ++p) { 34 if (0x0 == (*p & 0x80)) { 35 *pp = p + 1; 36 return true; 37 } 38 } 39 return false; 40 } 41 42 //===----------------------------------------------------------------------===// 43 // EhFrameReader 44 //===----------------------------------------------------------------------===// 45 template<> EhFrameReader::Token 46 EhFrameReader::scan<true>(ConstAddress pHandler, 47 uint64_t pOffset, 48 const MemoryRegion& pData) const 49 { 50 Token result; 51 result.file_off = pOffset; 52 53 const uint32_t* data = (const uint32_t*)pHandler; 54 size_t cur_idx = 0; 55 56 // Length Field 57 uint32_t length = data[cur_idx++]; 58 if (0x0 == length) { 59 // terminator 60 result.kind = Terminator; 61 result.data_off = 4; 62 result.size = 4; 63 return result; 64 } 65 66 // Extended Field 67 uint64_t extended = 0x0; 68 if (0xFFFFFFFF == length) { 69 extended = data[cur_idx++]; 70 extended <<= 32; 71 extended |= data[cur_idx++]; 72 result.size = extended + 12; 73 result.data_off = 16; 74 } 75 else { 76 result.size = length + 4; 77 result.data_off = 8; 78 } 79 80 // ID Field 81 uint32_t ID = data[cur_idx++]; 82 if (0x0 == ID) 83 result.kind = CIE; 84 else 85 result.kind = FDE; 86 87 return result; 88 } 89 90 template<> 91 bool EhFrameReader::read<32, true>(Input& pInput, EhFrame& pEhFrame) 92 { 93 // Alphabet: 94 // {CIE, FDE, CIEt} 95 // 96 // Regular Expression: 97 // (CIE FDE*)+ CIEt 98 // 99 // Autometa: 100 // S = {Q0, Q1, Q2}, Start = Q0, Accept = Q2 101 // 102 // FDE 103 // +---+ 104 // CIE \ / CIEt 105 // Q0 -------> Q1 -------> Q2 106 // | / \ ^ 107 // | +---+ | 108 // | CIE | 109 // +-----------------------+ 110 // CIEt 111 const State autometa[NumOfStates][NumOfTokenKinds] = { 112 // CIE FDE Term Unknown 113 { Q1, Reject, Accept, Reject }, // Q0 114 { Q1, Q1, Accept, Reject }, // Q1 115 }; 116 117 const Action transition[NumOfStates][NumOfTokenKinds] = { 118 /* CIE FDE Term Unknown */ 119 { addCIE, reject, addTerm, reject}, // Q0 120 { addCIE, addFDE, addTerm, reject}, // Q1 121 }; 122 123 // get file offset and address 124 LDSection& section = pEhFrame.getSection(); 125 uint64_t file_off = pInput.fileOffset() + section.offset(); 126 MemoryRegion* sect_reg = 127 pInput.memArea()->request(file_off, section.size()); 128 ConstAddress handler = (ConstAddress)sect_reg->start(); 129 130 State cur_state = Q0; 131 while (Reject != cur_state && Accept != cur_state) { 132 133 Token token = scan<true>(handler, file_off, *sect_reg); 134 MemoryRegion* entry = pInput.memArea()->request(token.file_off, token.size); 135 136 if (!transition[cur_state][token.kind](pEhFrame, *entry, token)) { 137 // fail to scan 138 debug(diag::debug_cannot_scan_eh) << pInput.name(); 139 return false; 140 } 141 142 file_off += token.size; 143 handler += token.size; 144 145 if (handler == sect_reg->end()) 146 cur_state = Accept; 147 else if (handler > sect_reg->end()) { 148 cur_state = Reject; 149 } 150 else 151 cur_state = autometa[cur_state][token.kind]; 152 } // end of while 153 154 if (Reject == cur_state) { 155 // fail to parse 156 debug(diag::debug_cannot_parse_eh) << pInput.name(); 157 return false; 158 } 159 return true; 160 } 161 162 bool EhFrameReader::addCIE(EhFrame& pEhFrame, 163 MemoryRegion& pRegion, 164 const EhFrameReader::Token& pToken) 165 { 166 // skip Length, Extended Length and CIE ID. 167 ConstAddress handler = pRegion.start() + pToken.data_off; 168 ConstAddress cie_end = pRegion.end(); 169 170 // the version should be 1 or 3 171 uint8_t version = *handler++; 172 if (1 != version && 3 != version) { 173 return false; 174 } 175 176 // Set up the Augumentation String 177 ConstAddress aug_str_front = handler; 178 ConstAddress aug_str_back = static_cast<ConstAddress>( 179 memchr(aug_str_front, '\0', cie_end - aug_str_front)); 180 if (NULL == aug_str_back) { 181 return false; 182 } 183 184 llvm::StringRef augment((const char*)aug_str_front); 185 186 // skip the Augumentation String field 187 handler = aug_str_back + 1; 188 189 // skip the Code Alignment Factor 190 if (!skip_LEB128(&handler, cie_end)) { 191 return false; 192 } 193 // skip the Data Alignment Factor 194 if (!skip_LEB128(&handler, cie_end)) { 195 return false; 196 } 197 // skip the Return Address Register 198 if (cie_end - handler < 1) { 199 return false; 200 } 201 ++handler; 202 203 // the Augmentation String start with 'eh' is a CIE from gcc before 3.0, 204 // in LSB Core Spec 3.0RC1. We do not support it. 205 if (augment[0] == 'e' && augment[1] == 'h') { 206 return false; 207 } 208 209 // parse the Augmentation String to get the FDE encodeing if 'z' existed 210 uint8_t fde_encoding = llvm::dwarf::DW_EH_PE_absptr; 211 if ('z' == augment[0]) { 212 213 // skip the Augumentation Data Length 214 if (!skip_LEB128(&handler, cie_end)) { 215 return false; 216 } 217 218 // parse the Augmentation String 219 for (size_t i = 1; i < augment.size(); ++i) { 220 switch (augment[i]) { 221 // LDSA encoding (1 byte) 222 case 'L': { 223 if (cie_end - handler < 1) { 224 return false; 225 } 226 ++handler; 227 break; 228 } 229 // Two arguments, the first one represents the encoding of the second 230 // argument (1 byte). The second one is the address of personality 231 // routine. 232 case 'P': { 233 // the first argument 234 if (cie_end - handler < 1) { 235 return false; 236 } 237 uint8_t per_encode = *handler; 238 ++handler; 239 // get the length of the second argument 240 uint32_t per_length = 0; 241 if (0x60 == (per_encode & 0x60)) { 242 return false; 243 } 244 switch (per_encode & 7) { 245 default: 246 return false; 247 case llvm::dwarf::DW_EH_PE_udata2: 248 per_length = 2; 249 break; 250 case llvm::dwarf::DW_EH_PE_udata4: 251 per_length = 4; 252 break; 253 case llvm::dwarf::DW_EH_PE_udata8: 254 per_length = 8; 255 break; 256 case llvm::dwarf::DW_EH_PE_absptr: 257 per_length = 4; // pPkg.bitclass / 8; 258 break; 259 } 260 // skip the alignment 261 if (llvm::dwarf::DW_EH_PE_aligned == (per_encode & 0xf0)) { 262 uint32_t per_align = handler - cie_end; 263 per_align += per_length - 1; 264 per_align &= ~(per_length -1); 265 if (static_cast<uint32_t>(cie_end - handler) < per_align) { 266 return false; 267 } 268 handler += per_align; 269 } 270 // skip the second argument 271 if (static_cast<uint32_t>(cie_end - handler) < per_length) { 272 return false; 273 } 274 handler += per_length; 275 break; 276 } // end of case 'P' 277 278 // FDE encoding (1 byte) 279 case 'R': { 280 if (cie_end - handler < 1) { 281 return false; 282 } 283 fde_encoding = *handler; 284 switch (fde_encoding & 7) { 285 case llvm::dwarf::DW_EH_PE_udata2: 286 case llvm::dwarf::DW_EH_PE_udata4: 287 case llvm::dwarf::DW_EH_PE_udata8: 288 case llvm::dwarf::DW_EH_PE_absptr: 289 break; 290 default: 291 return false; 292 } 293 ++handler; 294 break; 295 } 296 default: 297 return false; 298 } // end switch 299 } // the rest chars. 300 } // first char is 'z' 301 302 // create and push back the CIE entry 303 EhFrame::CIE* cie = new EhFrame::CIE(pRegion); 304 cie->setFDEEncode(fde_encoding); 305 pEhFrame.addCIE(*cie); 306 return true; 307 } 308 309 bool EhFrameReader::addFDE(EhFrame& pEhFrame, 310 MemoryRegion& pRegion, 311 const EhFrameReader::Token& pToken) 312 { 313 if (pToken.data_off == pRegion.size()) 314 return false; 315 316 // create and push back the FDE entry 317 EhFrame::FDE* fde = new EhFrame::FDE(pRegion, 318 pEhFrame.cie_back(), 319 pToken.data_off); 320 pEhFrame.addFDE(*fde); 321 return true; 322 } 323 324 bool EhFrameReader::addTerm(EhFrame& pEhFrame, 325 MemoryRegion& pRegion, 326 const EhFrameReader::Token& pToken) 327 { 328 RegionFragment* frag = new RegionFragment(pRegion); 329 pEhFrame.addFragment(*frag); 330 return true; 331 } 332 333 bool EhFrameReader::reject(EhFrame& pEhFrame, 334 MemoryRegion& pRegion, 335 const EhFrameReader::Token& pToken) 336 { 337 return true; 338 } 339 340