OLD | NEW |
(Empty) | |
| 1 //===-- NaClObjDumpStream.cpp --------------------------------------------===// |
| 2 // Implements an objdump stream (bitcode records/assembly code). |
| 3 // |
| 4 // The LLVM Compiler Infrastructure |
| 5 // |
| 6 // This file is distributed under the University of Illinois Open Source |
| 7 // License. See LICENSE.TXT for details. |
| 8 // |
| 9 //===----------------------------------------------------------------------===// |
| 10 |
| 11 #include "llvm/ADT/STLExtras.h" |
| 12 #include "llvm/Bitcode/NaCl/NaClObjDumpStream.h" |
| 13 #include "llvm/Support/DataTypes.h" |
| 14 #include "llvm/Support/ErrorHandling.h" |
| 15 #include "llvm/Support/Format.h" |
| 16 |
| 17 namespace llvm { |
| 18 namespace naclbitc { |
| 19 |
| 20 TextFormatter::TextFormatter(raw_ostream &BaseStream, |
| 21 unsigned LineWidth, |
| 22 const char *Tab) |
| 23 : TextIndenter(Tab), |
| 24 BaseStream(BaseStream), |
| 25 TextStream(TextBuffer), |
| 26 LineWidth(LineWidth), |
| 27 LinePosition(0), |
| 28 CurrentIndent(0), |
| 29 MinLineWidth(20), |
| 30 AtInstructionBeginning(true), |
| 31 LineIndent(), |
| 32 ContinuationIndent(), |
| 33 ClusteringLevel(0), |
| 34 ClusteredTextSize(0) { |
| 35 if (MinLineWidth > LineWidth) MinLineWidth = LineWidth; |
| 36 } |
| 37 |
| 38 TextFormatter::~TextFormatter() {} |
| 39 |
| 40 void TextFormatter::WriteEndline() { |
| 41 assert(!IsClustering() && "Must close clustering before ending instruction"); |
| 42 Write('\n'); |
| 43 CurrentIndent = 0; |
| 44 AtInstructionBeginning = true; |
| 45 LineIndent.clear(); |
| 46 } |
| 47 |
| 48 std::string TextFormatter::GetToken() { |
| 49 TextStream.flush(); |
| 50 std::string Token(TextBuffer); |
| 51 TextBuffer.clear(); |
| 52 if (!Token.empty() && IsClustering()) |
| 53 AppendForReplay(GetTokenDirective::Allocate(this, Token)); |
| 54 return Token; |
| 55 } |
| 56 |
| 57 void TextFormatter::Write(char ch) { |
| 58 switch (ch) { |
| 59 case '\n': |
| 60 BaseStream << ch; |
| 61 LinePosition = 0; |
| 62 break; |
| 63 case '\t': { |
| 64 size_t TabWidth = GetTabSize(); |
| 65 size_t NumChars = LinePosition % TabWidth; |
| 66 if (NumChars == 0) NumChars = TabWidth; |
| 67 for (size_t i = 0; i < NumChars; ++i) Write(' '); |
| 68 break; |
| 69 } |
| 70 default: |
| 71 if (LinePosition == 0) { |
| 72 WriteLineIndents(); |
| 73 } |
| 74 BaseStream << ch; |
| 75 ++LinePosition; |
| 76 } |
| 77 AtInstructionBeginning = false; |
| 78 } |
| 79 |
| 80 void TextFormatter::Write(const std::string &Text) { |
| 81 if (IsClustering()) { |
| 82 ClusteredTextSize += Text.size(); |
| 83 } else { |
| 84 for (std::string::const_iterator |
| 85 Iter = Text.begin(), IterEnd = Text.end(); |
| 86 Iter != IterEnd; ++Iter) { |
| 87 Write(*Iter); |
| 88 } |
| 89 } |
| 90 } |
| 91 |
| 92 void TextFormatter::StartClustering() { |
| 93 ++ClusteringLevel; |
| 94 } |
| 95 |
| 96 void TextFormatter::FinishClustering() { |
| 97 assert(IsClustering() && "Can't finish clustering, not in cluster!"); |
| 98 --ClusteringLevel; |
| 99 if (IsClustering()) return; |
| 100 |
| 101 AddLineWrapIfNeeded(ClusteredTextSize); |
| 102 |
| 103 // Reapply the directives to generate the token text, and set |
| 104 // indentations. Because clustering can be nested, duplicate before |
| 105 // replaying, so that nested clusters can replayed and build its own |
| 106 // list of clustered directives. |
| 107 std::vector<const Directive*> Directives(ClusteredDirectives); |
| 108 ClusteredDirectives.clear(); |
| 109 ClusteredTextSize = 0; |
| 110 for (std::vector<const Directive*>::iterator |
| 111 Iter = Directives.begin(), |
| 112 IterEnd = Directives.end(); |
| 113 Iter != IterEnd; ++Iter) { |
| 114 (*Iter)->Apply(); |
| 115 } |
| 116 } |
| 117 |
| 118 void TextFormatter::WriteLineIndents() { |
| 119 // Add line indent to base stream. |
| 120 if (AtInstructionBeginning) LineIndent = GetIndent(); |
| 121 BaseStream << LineIndent; |
| 122 LinePosition += LineIndent.size(); |
| 123 |
| 124 // If not the first line, and local indent not set, add continuation |
| 125 // indent to the base stream. |
| 126 unsigned UseIndent = CurrentIndent; |
| 127 if (!AtInstructionBeginning && CurrentIndent == 0) { |
| 128 UseIndent = FixIndentValue(LinePosition + ContinuationIndent.size()); |
| 129 } |
| 130 |
| 131 // Add any additional indents local to the current instruction |
| 132 // being dumped to the base stream. |
| 133 for (; LinePosition < UseIndent; ++LinePosition) { |
| 134 BaseStream << ' '; |
| 135 } |
| 136 } |
| 137 |
| 138 void TextFormatter::Directive::Reapply() const { |
| 139 // Note: We don't want to store top-level start/finish cluster |
| 140 // directives on ClusteredDirectives, so that nested replays won't |
| 141 // reapply them. |
| 142 bool WasClustering = IsClustering(); |
| 143 MyApply(true); |
| 144 if (WasClustering && IsClustering()) |
| 145 Formatter->ClusteredDirectives.push_back(this); |
| 146 } |
| 147 |
| 148 |
| 149 TextFormatter::Directive *TextFormatter::GetTokenDirective:: |
| 150 Allocate(TextFormatter *Formatter, const std::string &Text) { |
| 151 GetTokenDirective *Dir = Formatter->GetTokenFreeList.Allocate(Formatter); |
| 152 Dir->Text = Text; |
| 153 return Dir; |
| 154 } |
| 155 |
| 156 RecordTextFormatter::RecordTextFormatter(ObjDumpStream *ObjDump) |
| 157 : TextFormatter(ObjDump->Records(), 0, " "), |
| 158 ObjDump(ObjDump), |
| 159 OpenBrace(this, "<"), |
| 160 CloseBrace(this, ">"), |
| 161 Comma(this, ","), |
| 162 Space(this), |
| 163 Endline(this), |
| 164 StartCluster(this), |
| 165 FinishCluster(this) { |
| 166 // Handle fact that 64-bit values can take up to 21 characters. |
| 167 MinLineWidth = 21; |
| 168 Label = RecordAddress(0); |
| 169 } |
| 170 |
| 171 std::string RecordTextFormatter::RecordAddress(uint64_t Bit, |
| 172 unsigned MinByteWidth) { |
| 173 std::string Buffer; |
| 174 raw_string_ostream Stream(Buffer); |
| 175 Stream << '%' << MinByteWidth << PRIu64 << ":%u"; |
| 176 Stream.flush(); |
| 177 std::string FormatString(Buffer); |
| 178 Buffer.clear(); |
| 179 Stream << format(FormatString.c_str(), |
| 180 (Bit / 8), |
| 181 static_cast<unsigned>(Bit % 8)); |
| 182 return Stream.str(); |
| 183 } |
| 184 |
| 185 std::string RecordTextFormatter::GetEmptyLabelColumn() { |
| 186 std::string Buffer; |
| 187 raw_string_ostream StrmBuffer(Buffer); |
| 188 for (size_t i = 0; i < Label.size(); ++i) { |
| 189 StrmBuffer << ' '; |
| 190 } |
| 191 StrmBuffer << '|'; |
| 192 return StrmBuffer.str(); |
| 193 } |
| 194 |
| 195 void RecordTextFormatter::WriteLineIndents() { |
| 196 if (AtInstructionBeginning) { |
| 197 BaseStream << Label << '|'; |
| 198 } else { |
| 199 BaseStream << GetEmptyLabelColumn(); |
| 200 } |
| 201 LinePosition += Label.size() + 1; |
| 202 TextFormatter::WriteLineIndents(); |
| 203 } |
| 204 |
| 205 void RecordTextFormatter::WriteValues(uint64_t Bit, |
| 206 const llvm::NaClBitcodeValues &Values, |
| 207 int32_t AbbrevIndex) { |
| 208 Label = ObjDump->RecordAddress(Bit); |
| 209 if (AbbrevIndex != ABBREV_INDEX_NOT_SPECIFIED) { |
| 210 TextStream << AbbrevIndex << ":" << Space; |
| 211 } |
| 212 TextStream << OpenBrace; |
| 213 for (size_t i = 0; i < Values.size(); ++i) { |
| 214 if (i > 0) { |
| 215 TextStream << Comma << FinishCluster << Space; |
| 216 } |
| 217 TextStream << StartCluster << Values[i]; |
| 218 } |
| 219 // Note: Because of record codes, Values are never empty. Hence we |
| 220 // always need to finish the cluster for the last number printed. |
| 221 TextStream << FinishCluster << CloseBrace << Endline; |
| 222 } |
| 223 |
| 224 unsigned ObjDumpStream::DefaultMaxErrors = 20; |
| 225 |
| 226 unsigned ObjDumpStream::ComboObjDumpSeparatorColumn = 40; |
| 227 |
| 228 unsigned ObjDumpStream::RecordObjectDumpLength = 80; |
| 229 |
| 230 ObjDumpStream::ObjDumpStream(raw_ostream &Stream, |
| 231 bool DumpRecords, bool DumpAssembly) |
| 232 : Stream(Stream), |
| 233 DumpRecords(DumpRecords), |
| 234 DumpAssembly(DumpAssembly), |
| 235 NumErrors(0), |
| 236 MaxErrors(DefaultMaxErrors), |
| 237 RecordWidth(0), |
| 238 StartOffset(0), |
| 239 AssemblyBuffer(), |
| 240 AssemblyStream(AssemblyBuffer), |
| 241 MessageBuffer(), |
| 242 MessageStream(MessageBuffer), |
| 243 ColumnSeparator('|'), |
| 244 LastKnownBit(0), |
| 245 RecordBuffer(), |
| 246 RecordStream(RecordBuffer), |
| 247 RecordFormatter(this) { |
| 248 if (DumpRecords) { |
| 249 RecordWidth = DumpAssembly |
| 250 ? ComboObjDumpSeparatorColumn |
| 251 : RecordObjectDumpLength; |
| 252 RecordFormatter.SetLineWidth(RecordWidth); |
| 253 } |
| 254 } |
| 255 |
| 256 raw_ostream &ObjDumpStream::Error(uint64_t Bit) { |
| 257 LastKnownBit = Bit; |
| 258 if (NumErrors >= MaxErrors) |
| 259 Fatal(Bit, "Too many errors"); |
| 260 ++NumErrors; |
| 261 return PrintMessagePrefix("Error", Bit); |
| 262 } |
| 263 |
| 264 void ObjDumpStream::Fatal(uint64_t Bit, const std::string &Message) { |
| 265 LastKnownBit = Bit; |
| 266 if (!Message.empty()) |
| 267 PrintMessagePrefix("Error", Bit) << Message << "\n"; |
| 268 Flush(); |
| 269 llvm::report_fatal_error("Unable to continue"); |
| 270 } |
| 271 |
| 272 void ObjDumpStream::Fatal(uint64_t Bit, |
| 273 const llvm::NaClBitcodeRecordData &Record, |
| 274 const std::string &Message) { |
| 275 LastKnownBit = Bit; |
| 276 PrintMessagePrefix("Error", Bit) << Message; |
| 277 Write(Bit, Record); |
| 278 llvm::report_fatal_error("Unable to continue"); |
| 279 } |
| 280 |
| 281 // Dumps the next line of text in the buffer. Returns the number of characters |
| 282 // printed. |
| 283 static size_t DumpLine(raw_ostream &Stream, |
| 284 const std::string &Buffer, |
| 285 size_t &Index, |
| 286 size_t Size) { |
| 287 size_t Count = 0; |
| 288 while (Index < Size) { |
| 289 char ch = Buffer[Index]; |
| 290 if (ch == '\n') { |
| 291 // At end of line, stop here. |
| 292 ++Index; |
| 293 return Count; |
| 294 } else { |
| 295 Stream << ch; |
| 296 ++Index; |
| 297 ++Count; |
| 298 } |
| 299 } |
| 300 return Count; |
| 301 } |
| 302 |
| 303 void ObjDumpStream::Flush() { |
| 304 // Start by flushing all buffers, so that we know the |
| 305 // text that must be written. |
| 306 RecordStream.flush(); |
| 307 AssemblyStream.flush(); |
| 308 MessageStream.flush(); |
| 309 |
| 310 // See if there is any record/assembly lines to print. |
| 311 if ((DumpRecords && !RecordBuffer.empty()) |
| 312 || (DumpAssembly && !AssemblyBuffer.empty())) { |
| 313 size_t RecordIndex = 0; |
| 314 size_t RecordSize = DumpRecords ? RecordBuffer.size() : 0; |
| 315 size_t AssemblyIndex = 0; |
| 316 size_t AssemblySize = DumpAssembly ? AssemblyBuffer.size() : 0; |
| 317 |
| 318 while (RecordIndex < RecordSize || AssemblyIndex < AssemblySize) { |
| 319 // Dump next record line. |
| 320 size_t Column = DumpLine(Stream, RecordBuffer, RecordIndex, RecordSize); |
| 321 // Now move to separator if assembly is to be printed also. |
| 322 if (DumpRecords && DumpAssembly) { |
| 323 if (Column == 0) { |
| 324 // Add indent filler. |
| 325 std::string Label = RecordFormatter.GetEmptyLabelColumn(); |
| 326 Stream << Label; |
| 327 Column += Label.size(); |
| 328 } |
| 329 for (size_t i = Column; i < RecordWidth; ++i) { |
| 330 Stream << ' '; |
| 331 } |
| 332 Stream << ColumnSeparator; |
| 333 } |
| 334 // Dump next assembly line. |
| 335 DumpLine(Stream, AssemblyBuffer, AssemblyIndex, AssemblySize); |
| 336 Stream << '\n'; |
| 337 } |
| 338 } |
| 339 |
| 340 // Print out messages and reset buffers. |
| 341 Stream << MessageBuffer; |
| 342 ResetBuffers(); |
| 343 if (NumErrors >= MaxErrors) { |
| 344 // Note: we don't call Fatal here because that will call Flush, causing |
| 345 // an infinite loop. |
| 346 Stream << "Error(" << ObjDumpAddress(LastKnownBit) |
| 347 << "): Too many errors\n"; |
| 348 llvm::report_fatal_error("Unable to continue"); |
| 349 } |
| 350 Stream.flush(); |
| 351 } |
| 352 |
| 353 } |
| 354 } |
OLD | NEW |