EhFrame.cpp revision affc150dc44fab1911775a49636d0ce85333b634
1//===- EhFrame.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/EhFrame.h> 10#include <mcld/MC/MCLinker.h> 11#include <mcld/Support/MsgHandling.h> 12#include <mcld/Target/TargetLDBackend.h> 13#include <llvm/Support/Dwarf.h> 14#include <llvm/Support/Host.h> 15 16using namespace mcld; 17 18//========================== 19// EhFrame 20EhFrame::EhFrame() 21 : m_fCanRecognizeAll(true) { 22} 23 24EhFrame::~EhFrame() 25{ 26} 27 28uint64_t EhFrame::readEhFrame(Layout& pLayout, 29 const TargetLDBackend& pBackend, 30 llvm::MCSectionData& pSD, 31 LDSection& pSection, 32 MemoryArea& pArea) 33{ 34 MemoryRegion* region = pArea.request(pSection.offset(), 35 pSection.size()); 36 // an empty .eh_frame 37 if (NULL == region) { 38 note(diag::note_ehframe) << "an empty eh_frame"; 39 return 0; 40 } 41 42 ConstAddress eh_start = region->start(); 43 ConstAddress eh_end = region->end(); 44 ConstAddress p = eh_start; 45 46 // read the Length filed 47 uint32_t len = readVal(p, pBackend.isLittleEndian()); 48 49 // This CIE is a terminator if the Length field is 0, return 0 to handled it 50 // as an ordinary input. 51 if (0 == len) { 52 note(diag::note_ehframe) << "a terminator"; 53 pArea.release(region); 54 return 0; 55 } 56 57 if (0xffffffff == len) { 58 debug(diag::debug_eh_unsupport) << "64-bit eh_frame"; 59 pArea.release(region); 60 m_fCanRecognizeAll = false; 61 return 0; 62 } 63 64 // record the order of the CIE and FDE fragments 65 FragListType frag_list; 66 67 while (p < eh_end) { 68 69 if (eh_end - p < 4) { 70 debug(diag::debug_eh_unsupport) << "CIE or FDE size smaller than 4"; 71 m_fCanRecognizeAll = false; 72 break; 73 } 74 // read the Length field 75 len = readVal(p, pBackend.isLittleEndian()); 76 p += 4; 77 78 // the zero length entry should be the end of the section 79 if (0 == len) { 80 if (p < eh_end) { 81 debug(diag::debug_eh_unsupport) << "Non-end entry with zero length"; 82 m_fCanRecognizeAll = false; 83 } 84 break; 85 } 86 if (0xffffffff == len) { 87 debug(diag::debug_eh_unsupport) << "64-bit eh_frame"; 88 m_fCanRecognizeAll = false; 89 break; 90 } 91 92 if (eh_end - p < 4) { 93 debug(diag::debug_eh_unsupport) << 94 "CIE:ID field / FDE: CIE Pointer field"; 95 m_fCanRecognizeAll = false; 96 break; 97 } 98 99 // compute the section offset of this entry 100 uint32_t ent_offset = static_cast<uint32_t>(p - eh_start - 4); 101 102 // get the MemoryRegion for this entry 103 MemoryRegion* ent_region = pArea.request(pSection.offset() + ent_offset, 104 len + 4); 105 106 // create and add a CIE or FDE entry 107 uint32_t id = readVal(p, pBackend.isLittleEndian()); 108 // CIE 109 if (0 == id) { 110 if (!addCIE(*ent_region, pBackend, frag_list)) { 111 m_fCanRecognizeAll = false; 112 pArea.release(ent_region); 113 break; 114 } 115 } 116 117 // FDE 118 else { 119 if (!addFDE(*ent_region, pBackend, frag_list)) { 120 m_fCanRecognizeAll = false; 121 pArea.release(ent_region); 122 break; 123 } 124 } 125 p += len; 126 } 127 128 if (!m_fCanRecognizeAll) { 129 pArea.release(region); 130 deleteFragments(frag_list, pArea); 131 return 0; 132 } 133 134 // append all CIE and FDE fragments to Layout after we successfully read 135 // this eh_frame 136 size_t section_size = 0; 137 for (FragListType::iterator it = frag_list.begin(); 138 it != frag_list.end(); ++it) 139 section_size += pLayout.appendFragment(**it, pSD, pSection.align()); 140 141 pArea.release(region); 142 return section_size; 143} 144 145bool EhFrame::addCIE(MemoryRegion& pRegion, 146 const TargetLDBackend& pBackend, 147 FragListType& pFragList) 148{ 149 ConstAddress cie_start = pRegion.start(); 150 ConstAddress cie_end = pRegion.end(); 151 ConstAddress p = cie_start; 152 153 // skip the Length (4 byte) and CIE ID (4 byte) fields 154 p += 8; 155 156 // the version should be 1 157 if (1 != *p) { 158 debug(diag::debug_eh_unsupport) << "CIE version"; 159 return false; 160 } 161 ++p; 162 163 // get the Augumentation String 164 ConstAddress aug_str = p; 165 ConstAddress aug_str_end = static_cast<ConstAddress>( 166 memchr(p, '\0', cie_end - p)); 167 168 // skip the Augumentation String field 169 p = aug_str_end + 1; 170 171 // skip the Code Alignment Factor 172 if (!skipLEB128(&p, cie_end)) { 173 debug(diag::debug_eh_unsupport) << "unrecognized Code Alignment Factor"; 174 return false; 175 } 176 // skip the Data Alignment Factor 177 if (!skipLEB128(&p, cie_end)) { 178 debug(diag::debug_eh_unsupport) << "unrecognized Data Alignment Factor"; 179 return false; 180 } 181 // skip the Return Address Register 182 if (cie_end - p < 1) { 183 debug(diag::debug_eh_unsupport) << "unrecognized Return Address Register"; 184 return false; 185 } 186 ++p; 187 188 // the Augmentation String start with 'eh' is a CIE from gcc before 3.0, 189 // in LSB Core Spec 3.0RC1. We do not support it. 190 if (aug_str[0] == 'e' && aug_str[1] == 'h') { 191 debug(diag::debug_eh_unsupport) << "augmentation string `eh`"; 192 return false; 193 } 194 195 // parse the Augmentation String to get the FDE encodeing if 'z' existed 196 std::string aug_str_data; 197 uint8_t fde_encoding = llvm::dwarf::DW_EH_PE_absptr; 198 if (*aug_str == 'z') { 199 200 aug_str_data += *aug_str; 201 ++aug_str; 202 203 // skip the Augumentation Data Length 204 if (!skipLEB128(&p, cie_end)) { 205 debug(diag::debug_eh_unsupport) << 206 "unrecognized Augmentation Data Length"; 207 return false; 208 } 209 210 while (aug_str != aug_str_end) { 211 switch (*aug_str) { 212 default: 213 debug(diag::debug_eh_unsupport) << "augmentation string"; 214 return false; 215 216 // LDSA encoding (1 byte) 217 case 'L': 218 if (cie_end - p < 1) { 219 debug(diag::debug_eh_unsupport) << "augmentation string `L`"; 220 return false; 221 } 222 ++p; 223 break; 224 225 // Two arguments, the first one represents the encoding of the second 226 // argument (1 byte). The second one is the address of personality 227 // routine. 228 case 'P': { 229 // the first argument 230 if (cie_end - p < 1) { 231 debug(diag::debug_eh_unsupport) << "augmentation string `P`"; 232 return false; 233 } 234 uint8_t per_encode = *p; 235 ++p; 236 // get the length of the second argument 237 uint32_t per_length = 0; 238 if (0x60 == (per_encode & 0x60)) { 239 debug(diag::debug_eh_unsupport) << "augmentation string `P`"; 240 return false; 241 } 242 switch (per_encode & 7) { 243 default: 244 debug(diag::debug_eh_unsupport) << "augmentation string `P`"; 245 return false; 246 case llvm::dwarf::DW_EH_PE_udata2: 247 per_length = 2; 248 break; 249 case llvm::dwarf::DW_EH_PE_udata4: 250 per_length = 4; 251 break; 252 case llvm::dwarf::DW_EH_PE_udata8: 253 per_length = 8; 254 break; 255 case llvm::dwarf::DW_EH_PE_absptr: 256 per_length = pBackend.bitclass() / 8; 257 break; 258 } 259 // skip the alignment 260 if (llvm::dwarf::DW_EH_PE_aligned == (per_encode & 0xf0)) { 261 uint32_t per_align = p - cie_end; 262 per_align += per_length - 1; 263 per_align &= ~(per_length -1); 264 if (static_cast<uint32_t>(cie_end - p) < per_align) { 265 debug(diag::debug_eh_unsupport) << "augmentation string `P`"; 266 return false; 267 } 268 p += per_align; 269 } 270 // skip the second argument 271 if (static_cast<uint32_t>(cie_end - p) < per_length) { 272 debug(diag::debug_eh_unsupport) << "augmentation string `P`"; 273 return false; 274 } 275 p += per_length; 276 } 277 break; 278 279 // FDE encoding (1 byte) 280 case 'R': 281 if (cie_end - p < 1) { 282 debug(diag::debug_eh_unsupport) << "augmentation string `R`"; 283 return false; 284 } 285 fde_encoding = *p; 286 switch (fde_encoding & 7) { 287 case llvm::dwarf::DW_EH_PE_udata2: 288 case llvm::dwarf::DW_EH_PE_udata4: 289 case llvm::dwarf::DW_EH_PE_udata8: 290 case llvm::dwarf::DW_EH_PE_absptr: 291 break; 292 default: 293 debug(diag::debug_eh_unsupport) << "FDE encoding"; 294 return false; 295 } 296 ++p; 297 break; 298 } // end switch 299 aug_str_data += *aug_str; 300 ++aug_str; 301 } // end while 302 } 303 304 note(diag::note_eh_cie) << pRegion.size() 305 << aug_str_data 306 << (fde_encoding & 7); 307 308 // create and push back the CIE entry 309 CIE* entry = new CIE(pRegion, fde_encoding); 310 m_CIEs.push_back(entry); 311 pFragList.push_back(static_cast<llvm::MCFragment*>(entry)); 312 return true; 313} 314 315bool EhFrame::addFDE(MemoryRegion& pRegion, 316 const TargetLDBackend& pBackend, 317 FragListType& pFragList) 318{ 319 ConstAddress fde_start = pRegion.start(); 320 ConstAddress fde_end = pRegion.end(); 321 ConstAddress p = fde_start; 322 323 // skip the Length (4 byte) and CIE Pointer (4 byte) fields 324 p += 8; 325 326 // get the entry offset of the PC Begin 327 if (fde_end - p < 1) { 328 debug(diag::debug_eh_unsupport) << "FDE PC Begin"; 329 return false; 330 } 331 FDE::Offset pc_offset = static_cast<FDE::Offset>(p - fde_start); 332 333 note(diag::note_eh_fde) << pRegion.size() << pc_offset; 334 // create and push back the FDE entry 335 FDE* entry = new FDE(pRegion, **(m_CIEs.end() -1), pc_offset); 336 m_FDEs.push_back(entry); 337 pFragList.push_back(static_cast<llvm::MCFragment*>(entry)); 338 return true; 339} 340 341uint32_t EhFrame::readVal(ConstAddress pAddr, bool pIsTargetLittleEndian) 342{ 343 const uint32_t* p = reinterpret_cast<const uint32_t*>(pAddr); 344 uint32_t val = *p; 345 346 // byte swapping if the host and target have different endian 347 if (llvm::sys::isLittleEndianHost() != pIsTargetLittleEndian) 348 val = bswap32(val); 349 return val; 350} 351 352bool EhFrame::skipLEB128(ConstAddress* pp, ConstAddress pend) 353{ 354 for (ConstAddress p = *pp; p < pend; ++p) { 355 if (0 == (*p & 0x80)) { 356 *pp = p + 1; 357 return true; 358 } 359 } 360 return false; 361} 362 363void EhFrame::deleteFragments(FragListType& pList, MemoryArea& pArea) 364{ 365 MCRegionFragment* frag = NULL; 366 for (FragListType::iterator it = pList.begin(); it != pList.end(); ++it) { 367 frag = static_cast<MCRegionFragment*>(*it); 368 pArea.release(&(frag->getRegion())); 369 delete *it; 370 } 371 pList.clear(); 372} 373 374