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