EhFrameReader.cpp revision f7ac0f19a1c8d0ad14bcf6456ce368b830fea886
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 20using namespace mcld; 21using 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. 30static bool 31skip_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//===----------------------------------------------------------------------===// 45template<> EhFrameReader::Token 46EhFrameReader::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 90template<> 91bool 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 LDSection& section = pEhFrame.getSection(); 124 if (section.size() == 0x0) { 125 NullFragment* frag = new NullFragment(); 126 pEhFrame.addFragment(*frag); 127 return true; 128 } 129 130 // get file offset and address 131 uint64_t file_off = pInput.fileOffset() + section.offset(); 132 MemoryRegion* sect_reg = 133 pInput.memArea()->request(file_off, section.size()); 134 ConstAddress handler = (ConstAddress)sect_reg->start(); 135 136 State cur_state = Q0; 137 while (Reject != cur_state && Accept != cur_state) { 138 139 Token token = scan<true>(handler, file_off, *sect_reg); 140 MemoryRegion* entry = pInput.memArea()->request(token.file_off, token.size); 141 142 if (!transition[cur_state][token.kind](pEhFrame, *entry, token)) { 143 // fail to scan 144 debug(diag::debug_cannot_scan_eh) << pInput.name(); 145 return false; 146 } 147 148 file_off += token.size; 149 handler += token.size; 150 151 if (handler == sect_reg->end()) 152 cur_state = Accept; 153 else if (handler > sect_reg->end()) { 154 cur_state = Reject; 155 } 156 else 157 cur_state = autometa[cur_state][token.kind]; 158 } // end of while 159 160 if (Reject == cur_state) { 161 // fail to parse 162 debug(diag::debug_cannot_parse_eh) << pInput.name(); 163 return false; 164 } 165 return true; 166} 167 168bool EhFrameReader::addCIE(EhFrame& pEhFrame, 169 MemoryRegion& pRegion, 170 const EhFrameReader::Token& pToken) 171{ 172 // skip Length, Extended Length and CIE ID. 173 ConstAddress handler = pRegion.start() + pToken.data_off; 174 ConstAddress cie_end = pRegion.end(); 175 176 // the version should be 1 or 3 177 uint8_t version = *handler++; 178 if (1 != version && 3 != version) { 179 return false; 180 } 181 182 // Set up the Augumentation String 183 ConstAddress aug_str_front = handler; 184 ConstAddress aug_str_back = static_cast<ConstAddress>( 185 memchr(aug_str_front, '\0', cie_end - aug_str_front)); 186 if (NULL == aug_str_back) { 187 return false; 188 } 189 190 // skip the Augumentation String field 191 handler = aug_str_back + 1; 192 193 // skip the Code Alignment Factor 194 if (!skip_LEB128(&handler, cie_end)) { 195 return false; 196 } 197 // skip the Data Alignment Factor 198 if (!skip_LEB128(&handler, cie_end)) { 199 return false; 200 } 201 // skip the Return Address Register 202 if (cie_end - handler < 1) { 203 return false; 204 } 205 ++handler; 206 207 llvm::StringRef augment((const char*)aug_str_front); 208 209 // we discard this CIE if the augumentation string is '\0' 210 if (0 == augment.size()) { 211 EhFrame::CIE* cie = new EhFrame::CIE(pRegion); 212 cie->setFDEEncode(llvm::dwarf::DW_EH_PE_absptr); 213 pEhFrame.addCIE(*cie); 214 return true; 215 } 216 217 // the Augmentation String start with 'eh' is a CIE from gcc before 3.0, 218 // in LSB Core Spec 3.0RC1. We do not support it. 219 if (augment.size() > 1 && augment[0] == 'e' && augment[1] == 'h') { 220 return false; 221 } 222 223 // parse the Augmentation String to get the FDE encodeing if 'z' existed 224 uint8_t fde_encoding = llvm::dwarf::DW_EH_PE_absptr; 225 if ('z' == augment[0]) { 226 227 // skip the Augumentation Data Length 228 if (!skip_LEB128(&handler, cie_end)) { 229 return false; 230 } 231 232 // parse the Augmentation String 233 for (size_t i = 1; i < augment.size(); ++i) { 234 switch (augment[i]) { 235 // LDSA encoding (1 byte) 236 case 'L': { 237 if (cie_end - handler < 1) { 238 return false; 239 } 240 ++handler; 241 break; 242 } 243 // Two arguments, the first one represents the encoding of the second 244 // argument (1 byte). The second one is the address of personality 245 // routine. 246 case 'P': { 247 // the first argument 248 if (cie_end - handler < 1) { 249 return false; 250 } 251 uint8_t per_encode = *handler; 252 ++handler; 253 // get the length of the second argument 254 uint32_t per_length = 0; 255 if (0x60 == (per_encode & 0x60)) { 256 return false; 257 } 258 switch (per_encode & 7) { 259 default: 260 return false; 261 case llvm::dwarf::DW_EH_PE_udata2: 262 per_length = 2; 263 break; 264 case llvm::dwarf::DW_EH_PE_udata4: 265 per_length = 4; 266 break; 267 case llvm::dwarf::DW_EH_PE_udata8: 268 per_length = 8; 269 break; 270 case llvm::dwarf::DW_EH_PE_absptr: 271 per_length = 4; // pPkg.bitclass / 8; 272 break; 273 } 274 // skip the alignment 275 if (llvm::dwarf::DW_EH_PE_aligned == (per_encode & 0xf0)) { 276 uint32_t per_align = handler - cie_end; 277 per_align += per_length - 1; 278 per_align &= ~(per_length -1); 279 if (static_cast<uint32_t>(cie_end - handler) < per_align) { 280 return false; 281 } 282 handler += per_align; 283 } 284 // skip the second argument 285 if (static_cast<uint32_t>(cie_end - handler) < per_length) { 286 return false; 287 } 288 handler += per_length; 289 break; 290 } // end of case 'P' 291 292 // FDE encoding (1 byte) 293 case 'R': { 294 if (cie_end - handler < 1) { 295 return false; 296 } 297 fde_encoding = *handler; 298 switch (fde_encoding & 7) { 299 case llvm::dwarf::DW_EH_PE_udata2: 300 case llvm::dwarf::DW_EH_PE_udata4: 301 case llvm::dwarf::DW_EH_PE_udata8: 302 case llvm::dwarf::DW_EH_PE_absptr: 303 break; 304 default: 305 return false; 306 } 307 ++handler; 308 break; 309 } 310 default: 311 return false; 312 } // end switch 313 } // the rest chars. 314 } // first char is 'z' 315 316 // create and push back the CIE entry 317 EhFrame::CIE* cie = new EhFrame::CIE(pRegion); 318 cie->setFDEEncode(fde_encoding); 319 pEhFrame.addCIE(*cie); 320 return true; 321} 322 323bool EhFrameReader::addFDE(EhFrame& pEhFrame, 324 MemoryRegion& pRegion, 325 const EhFrameReader::Token& pToken) 326{ 327 if (pToken.data_off == pRegion.size()) 328 return false; 329 330 // create and push back the FDE entry 331 EhFrame::FDE* fde = new EhFrame::FDE(pRegion, 332 pEhFrame.cie_back(), 333 pToken.data_off); 334 pEhFrame.addFDE(*fde); 335 return true; 336} 337 338bool EhFrameReader::addTerm(EhFrame& pEhFrame, 339 MemoryRegion& pRegion, 340 const EhFrameReader::Token& pToken) 341{ 342 RegionFragment* frag = new RegionFragment(pRegion); 343 pEhFrame.addFragment(*frag); 344 return true; 345} 346 347bool EhFrameReader::reject(EhFrame& pEhFrame, 348 MemoryRegion& pRegion, 349 const EhFrameReader::Token& pToken) 350{ 351 return true; 352} 353 354