LLVM API Documentation
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