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