Home | History | Annotate | Download | only in LD
      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