LLVM API Documentation

DwarfAccelTable.cpp
Go to the documentation of this file.
00001 //=-- llvm/CodeGen/DwarfAccelTable.cpp - Dwarf Accelerator Tables -*- C++ -*-=//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file contains support for writing dwarf accelerator tables.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #include "DwarfAccelTable.h"
00015 #include "DIE.h"
00016 #include "DwarfDebug.h"
00017 #include "llvm/ADT/STLExtras.h"
00018 #include "llvm/ADT/Twine.h"
00019 #include "llvm/CodeGen/AsmPrinter.h"
00020 #include "llvm/MC/MCExpr.h"
00021 #include "llvm/MC/MCStreamer.h"
00022 #include "llvm/MC/MCSymbol.h"
00023 #include "llvm/Support/Debug.h"
00024 
00025 using namespace llvm;
00026 
00027 // The length of the header data is always going to be 4 + 4 + 4*NumAtoms.
00028 DwarfAccelTable::DwarfAccelTable(ArrayRef<DwarfAccelTable::Atom> atomList)
00029     : Header(8 + (atomList.size() * 4)), HeaderData(atomList),
00030       Entries(Allocator) {}
00031 
00032 void DwarfAccelTable::AddName(StringRef Name, MCSymbol *StrSym, const DIE *die,
00033                               char Flags) {
00034   assert(Data.empty() && "Already finalized!");
00035   // If the string is in the list already then add this die to the list
00036   // otherwise add a new one.
00037   DataArray &DIEs = Entries[Name];
00038   assert(!DIEs.StrSym || DIEs.StrSym == StrSym);
00039   DIEs.StrSym = StrSym;
00040   DIEs.Values.push_back(new (Allocator) HashDataContents(die, Flags));
00041 }
00042 
00043 void DwarfAccelTable::ComputeBucketCount(void) {
00044   // First get the number of unique hashes.
00045   std::vector<uint32_t> uniques(Data.size());
00046   for (size_t i = 0, e = Data.size(); i < e; ++i)
00047     uniques[i] = Data[i]->HashValue;
00048   array_pod_sort(uniques.begin(), uniques.end());
00049   std::vector<uint32_t>::iterator p =
00050       std::unique(uniques.begin(), uniques.end());
00051   uint32_t num = std::distance(uniques.begin(), p);
00052 
00053   // Then compute the bucket size, minimum of 1 bucket.
00054   if (num > 1024)
00055     Header.bucket_count = num / 4;
00056   if (num > 16)
00057     Header.bucket_count = num / 2;
00058   else
00059     Header.bucket_count = num > 0 ? num : 1;
00060 
00061   Header.hashes_count = num;
00062 }
00063 
00064 // compareDIEs - comparison predicate that sorts DIEs by their offset.
00065 static bool compareDIEs(const DwarfAccelTable::HashDataContents *A,
00066                         const DwarfAccelTable::HashDataContents *B) {
00067   return A->Die->getOffset() < B->Die->getOffset();
00068 }
00069 
00070 void DwarfAccelTable::FinalizeTable(AsmPrinter *Asm, StringRef Prefix) {
00071   // Create the individual hash data outputs.
00072   for (StringMap<DataArray>::iterator EI = Entries.begin(), EE = Entries.end();
00073        EI != EE; ++EI) {
00074 
00075     // Unique the entries.
00076     std::stable_sort(EI->second.Values.begin(), EI->second.Values.end(), compareDIEs);
00077     EI->second.Values.erase(
00078         std::unique(EI->second.Values.begin(), EI->second.Values.end()),
00079         EI->second.Values.end());
00080 
00081     HashData *Entry = new (Allocator) HashData(EI->getKey(), EI->second);
00082     Data.push_back(Entry);
00083   }
00084 
00085   // Figure out how many buckets we need, then compute the bucket
00086   // contents and the final ordering. We'll emit the hashes and offsets
00087   // by doing a walk during the emission phase. We add temporary
00088   // symbols to the data so that we can reference them during the offset
00089   // later, we'll emit them when we emit the data.
00090   ComputeBucketCount();
00091 
00092   // Compute bucket contents and final ordering.
00093   Buckets.resize(Header.bucket_count);
00094   for (size_t i = 0, e = Data.size(); i < e; ++i) {
00095     uint32_t bucket = Data[i]->HashValue % Header.bucket_count;
00096     Buckets[bucket].push_back(Data[i]);
00097     Data[i]->Sym = Asm->GetTempSymbol(Prefix, i);
00098   }
00099 }
00100 
00101 // Emits the header for the table via the AsmPrinter.
00102 void DwarfAccelTable::EmitHeader(AsmPrinter *Asm) {
00103   Asm->OutStreamer.AddComment("Header Magic");
00104   Asm->EmitInt32(Header.magic);
00105   Asm->OutStreamer.AddComment("Header Version");
00106   Asm->EmitInt16(Header.version);
00107   Asm->OutStreamer.AddComment("Header Hash Function");
00108   Asm->EmitInt16(Header.hash_function);
00109   Asm->OutStreamer.AddComment("Header Bucket Count");
00110   Asm->EmitInt32(Header.bucket_count);
00111   Asm->OutStreamer.AddComment("Header Hash Count");
00112   Asm->EmitInt32(Header.hashes_count);
00113   Asm->OutStreamer.AddComment("Header Data Length");
00114   Asm->EmitInt32(Header.header_data_len);
00115   Asm->OutStreamer.AddComment("HeaderData Die Offset Base");
00116   Asm->EmitInt32(HeaderData.die_offset_base);
00117   Asm->OutStreamer.AddComment("HeaderData Atom Count");
00118   Asm->EmitInt32(HeaderData.Atoms.size());
00119   for (size_t i = 0; i < HeaderData.Atoms.size(); i++) {
00120     Atom A = HeaderData.Atoms[i];
00121     Asm->OutStreamer.AddComment(dwarf::AtomTypeString(A.type));
00122     Asm->EmitInt16(A.type);
00123     Asm->OutStreamer.AddComment(dwarf::FormEncodingString(A.form));
00124     Asm->EmitInt16(A.form);
00125   }
00126 }
00127 
00128 // Walk through and emit the buckets for the table. Each index is
00129 // an offset into the list of hashes.
00130 void DwarfAccelTable::EmitBuckets(AsmPrinter *Asm) {
00131   unsigned index = 0;
00132   for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
00133     Asm->OutStreamer.AddComment("Bucket " + Twine(i));
00134     if (Buckets[i].size() != 0)
00135       Asm->EmitInt32(index);
00136     else
00137       Asm->EmitInt32(UINT32_MAX);
00138     index += Buckets[i].size();
00139   }
00140 }
00141 
00142 // Walk through the buckets and emit the individual hashes for each
00143 // bucket.
00144 void DwarfAccelTable::EmitHashes(AsmPrinter *Asm) {
00145   for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
00146     for (HashList::const_iterator HI = Buckets[i].begin(),
00147                                   HE = Buckets[i].end();
00148          HI != HE; ++HI) {
00149       Asm->OutStreamer.AddComment("Hash in Bucket " + Twine(i));
00150       Asm->EmitInt32((*HI)->HashValue);
00151     }
00152   }
00153 }
00154 
00155 // Walk through the buckets and emit the individual offsets for each
00156 // element in each bucket. This is done via a symbol subtraction from the
00157 // beginning of the section. The non-section symbol will be output later
00158 // when we emit the actual data.
00159 void DwarfAccelTable::EmitOffsets(AsmPrinter *Asm, MCSymbol *SecBegin) {
00160   for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
00161     for (HashList::const_iterator HI = Buckets[i].begin(),
00162                                   HE = Buckets[i].end();
00163          HI != HE; ++HI) {
00164       Asm->OutStreamer.AddComment("Offset in Bucket " + Twine(i));
00165       MCContext &Context = Asm->OutStreamer.getContext();
00166       const MCExpr *Sub = MCBinaryExpr::CreateSub(
00167           MCSymbolRefExpr::Create((*HI)->Sym, Context),
00168           MCSymbolRefExpr::Create(SecBegin, Context), Context);
00169       Asm->OutStreamer.EmitValue(Sub, sizeof(uint32_t));
00170     }
00171   }
00172 }
00173 
00174 // Walk through the buckets and emit the full data for each element in
00175 // the bucket. For the string case emit the dies and the various offsets.
00176 // Terminate each HashData bucket with 0.
00177 void DwarfAccelTable::EmitData(AsmPrinter *Asm, DwarfFile *D,
00178                                MCSymbol *StrSym) {
00179   uint64_t PrevHash = UINT64_MAX;
00180   for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
00181     for (HashList::const_iterator HI = Buckets[i].begin(),
00182                                   HE = Buckets[i].end();
00183          HI != HE; ++HI) {
00184       // Remember to emit the label for our offset.
00185       Asm->OutStreamer.EmitLabel((*HI)->Sym);
00186       Asm->OutStreamer.AddComment((*HI)->Str);
00187       Asm->EmitSectionOffset((*HI)->Data.StrSym, StrSym);
00188       Asm->OutStreamer.AddComment("Num DIEs");
00189       Asm->EmitInt32((*HI)->Data.Values.size());
00190       for (HashDataContents *HD : (*HI)->Data.Values) {
00191         // Emit the DIE offset
00192         Asm->EmitInt32(HD->Die->getOffset());
00193         // If we have multiple Atoms emit that info too.
00194         // FIXME: A bit of a hack, we either emit only one atom or all info.
00195         if (HeaderData.Atoms.size() > 1) {
00196           Asm->EmitInt16(HD->Die->getTag());
00197           Asm->EmitInt8(HD->Flags);
00198         }
00199       }
00200       // Emit a 0 to terminate the data unless we have a hash collision.
00201       if (PrevHash != (*HI)->HashValue)
00202         Asm->EmitInt32(0);
00203       PrevHash = (*HI)->HashValue;
00204     }
00205   }
00206 }
00207 
00208 // Emit the entire data structure to the output file.
00209 void DwarfAccelTable::Emit(AsmPrinter *Asm, MCSymbol *SecBegin, DwarfFile *D,
00210                            MCSymbol *StrSym) {
00211   // Emit the header.
00212   EmitHeader(Asm);
00213 
00214   // Emit the buckets.
00215   EmitBuckets(Asm);
00216 
00217   // Emit the hashes.
00218   EmitHashes(Asm);
00219 
00220   // Emit the offsets.
00221   EmitOffsets(Asm, SecBegin);
00222 
00223   // Emit the hash data.
00224   EmitData(Asm, D, StrSym);
00225 }
00226 
00227 #ifndef NDEBUG
00228 void DwarfAccelTable::print(raw_ostream &O) {
00229 
00230   Header.print(O);
00231   HeaderData.print(O);
00232 
00233   O << "Entries: \n";
00234   for (StringMap<DataArray>::const_iterator EI = Entries.begin(),
00235                                             EE = Entries.end();
00236        EI != EE; ++EI) {
00237     O << "Name: " << EI->getKeyData() << "\n";
00238     for (HashDataContents *HD : EI->second.Values)
00239       HD->print(O);
00240   }
00241 
00242   O << "Buckets and Hashes: \n";
00243   for (size_t i = 0, e = Buckets.size(); i < e; ++i)
00244     for (HashList::const_iterator HI = Buckets[i].begin(),
00245                                   HE = Buckets[i].end();
00246          HI != HE; ++HI)
00247       (*HI)->print(O);
00248 
00249   O << "Data: \n";
00250   for (std::vector<HashData *>::const_iterator DI = Data.begin(),
00251                                                DE = Data.end();
00252        DI != DE; ++DI)
00253     (*DI)->print(O);
00254 }
00255 #endif