LLVM  10.0.0svn
MinidumpEmitter.cpp
Go to the documentation of this file.
1 //===- yaml2minidump.cpp - Convert a YAML file to a minidump file ---------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
13 
14 using namespace llvm;
15 using namespace llvm::minidump;
16 using namespace llvm::MinidumpYAML;
17 
18 namespace {
19 /// A helper class to manage the placement of various structures into the final
20 /// minidump binary. Space for objects can be allocated via various allocate***
21 /// methods, while the final minidump file is written by calling the writeTo
22 /// method. The plain versions of allocation functions take a reference to the
23 /// data which is to be written (and hence the data must be available until
24 /// writeTo is called), while the "New" versions allocate the data in an
25 /// allocator-managed buffer, which is available until the allocator object is
26 /// destroyed. For both kinds of functions, it is possible to modify the
27 /// data for which the space has been "allocated" until the final writeTo call.
28 /// This is useful for "linking" the allocated structures via their offsets.
29 class BlobAllocator {
30 public:
31  size_t tell() const { return NextOffset; }
32 
33  size_t allocateCallback(size_t Size,
34  std::function<void(raw_ostream &)> Callback) {
35  size_t Offset = NextOffset;
36  NextOffset += Size;
37  Callbacks.push_back(std::move(Callback));
38  return Offset;
39  }
40 
41  size_t allocateBytes(ArrayRef<uint8_t> Data) {
42  return allocateCallback(
43  Data.size(), [Data](raw_ostream &OS) { OS << toStringRef(Data); });
44  }
45 
46  size_t allocateBytes(yaml::BinaryRef Data) {
47  return allocateCallback(Data.binary_size(), [Data](raw_ostream &OS) {
48  Data.writeAsBinary(OS);
49  });
50  }
51 
52  template <typename T> size_t allocateArray(ArrayRef<T> Data) {
53  return allocateBytes({reinterpret_cast<const uint8_t *>(Data.data()),
54  sizeof(T) * Data.size()});
55  }
56 
57  template <typename T, typename RangeType>
58  std::pair<size_t, MutableArrayRef<T>>
59  allocateNewArray(const iterator_range<RangeType> &Range);
60 
61  template <typename T> size_t allocateObject(const T &Data) {
62  return allocateArray(makeArrayRef(Data));
63  }
64 
65  template <typename T, typename... Types>
66  std::pair<size_t, T *> allocateNewObject(Types &&... Args) {
67  T *Object = new (Temporaries.Allocate<T>()) T(std::forward<Types>(Args)...);
68  return {allocateObject(*Object), Object};
69  }
70 
71  size_t allocateString(StringRef Str);
72 
73  void writeTo(raw_ostream &OS) const;
74 
75 private:
76  size_t NextOffset = 0;
77 
78  BumpPtrAllocator Temporaries;
79  std::vector<std::function<void(raw_ostream &)>> Callbacks;
80 };
81 } // namespace
82 
83 template <typename T, typename RangeType>
84 std::pair<size_t, MutableArrayRef<T>>
85 BlobAllocator::allocateNewArray(const iterator_range<RangeType> &Range) {
86  size_t Num = std::distance(Range.begin(), Range.end());
87  MutableArrayRef<T> Array(Temporaries.Allocate<T>(Num), Num);
88  std::uninitialized_copy(Range.begin(), Range.end(), Array.begin());
89  return {allocateArray(Array), Array};
90 }
91 
92 size_t BlobAllocator::allocateString(StringRef Str) {
94  bool OK = convertUTF8ToUTF16String(Str, WStr);
95  assert(OK && "Invalid UTF8 in Str?");
96  (void)OK;
97 
98  // The utf16 string is null-terminated, but the terminator is not counted in
99  // the string size.
100  WStr.push_back(0);
101  size_t Result =
102  allocateNewObject<support::ulittle32_t>(2 * (WStr.size() - 1)).first;
103  allocateNewArray<support::ulittle16_t>(make_range(WStr.begin(), WStr.end()));
104  return Result;
105 }
106 
107 void BlobAllocator::writeTo(raw_ostream &OS) const {
108  size_t BeginOffset = OS.tell();
109  for (const auto &Callback : Callbacks)
110  Callback(OS);
111  assert(OS.tell() == BeginOffset + NextOffset &&
112  "Callbacks wrote an unexpected number of bytes.");
113  (void)BeginOffset;
114 }
115 
116 static LocationDescriptor layout(BlobAllocator &File, yaml::BinaryRef Data) {
117  return {support::ulittle32_t(Data.binary_size()),
118  support::ulittle32_t(File.allocateBytes(Data))};
119 }
120 
121 static void layout(BlobAllocator &File, MemoryListStream::entry_type &Range) {
122  Range.Entry.Memory = layout(File, Range.Content);
123 }
124 
125 static void layout(BlobAllocator &File, ModuleListStream::entry_type &M) {
126  M.Entry.ModuleNameRVA = File.allocateString(M.Name);
127 
128  M.Entry.CvRecord = layout(File, M.CvRecord);
129  M.Entry.MiscRecord = layout(File, M.MiscRecord);
130 }
131 
132 static void layout(BlobAllocator &File, ThreadListStream::entry_type &T) {
133  T.Entry.Stack.Memory = layout(File, T.Stack);
134  T.Entry.Context = layout(File, T.Context);
135 }
136 
137 template <typename EntryT>
138 static size_t layout(BlobAllocator &File,
140 
141  File.allocateNewObject<support::ulittle32_t>(S.Entries.size());
142  for (auto &E : S.Entries)
143  File.allocateObject(E.Entry);
144 
145  size_t DataEnd = File.tell();
146 
147  // Lay out the auxiliary data, (which is not a part of the stream).
148  DataEnd = File.tell();
149  for (auto &E : S.Entries)
150  layout(File, E);
151 
152  return DataEnd;
153 }
154 
155 static Directory layout(BlobAllocator &File, Stream &S) {
156  Directory Result;
157  Result.Type = S.Type;
158  Result.Location.RVA = File.tell();
159  Optional<size_t> DataEnd;
160  switch (S.Kind) {
161  case Stream::StreamKind::MemoryList:
162  DataEnd = layout(File, cast<MemoryListStream>(S));
163  break;
164  case Stream::StreamKind::ModuleList:
165  DataEnd = layout(File, cast<ModuleListStream>(S));
166  break;
167  case Stream::StreamKind::RawContent: {
168  RawContentStream &Raw = cast<RawContentStream>(S);
169  File.allocateCallback(Raw.Size, [&Raw](raw_ostream &OS) {
170  Raw.Content.writeAsBinary(OS);
171  assert(Raw.Content.binary_size() <= Raw.Size);
172  OS << std::string(Raw.Size - Raw.Content.binary_size(), '\0');
173  });
174  break;
175  }
176  case Stream::StreamKind::SystemInfo: {
177  SystemInfoStream &SystemInfo = cast<SystemInfoStream>(S);
178  File.allocateObject(SystemInfo.Info);
179  // The CSD string is not a part of the stream.
180  DataEnd = File.tell();
181  SystemInfo.Info.CSDVersionRVA = File.allocateString(SystemInfo.CSDVersion);
182  break;
183  }
184  case Stream::StreamKind::TextContent:
185  File.allocateArray(arrayRefFromStringRef(cast<TextContentStream>(S).Text));
186  break;
187  case Stream::StreamKind::ThreadList:
188  DataEnd = layout(File, cast<ThreadListStream>(S));
189  break;
190  }
191  // If DataEnd is not set, we assume everything we generated is a part of the
192  // stream.
193  Result.Location.DataSize =
194  DataEnd.getValueOr(File.tell()) - Result.Location.RVA;
195  return Result;
196 }
197 
198 namespace llvm {
199 namespace yaml {
200 
202  ErrorHandler /*EH*/) {
203  BlobAllocator File;
204  File.allocateObject(Obj.Header);
205 
206  std::vector<Directory> StreamDirectory(Obj.Streams.size());
208  File.allocateArray(makeArrayRef(StreamDirectory));
209  Obj.Header.NumberOfStreams = StreamDirectory.size();
210 
211  for (auto &Stream : enumerate(Obj.Streams))
212  StreamDirectory[Stream.index()] = layout(File, *Stream.value());
213 
214  File.writeTo(Out);
215  return true;
216 }
217 
218 } // namespace yaml
219 } // namespace llvm
SystemInfo minidump stream.
Definition: MinidumpYAML.h:121
This class represents lattice values for constants.
Definition: AllocatorList.h:23
Specifies the location (and size) of various objects in the minidump file.
Definition: Minidump.h:56
support::ulittle32_t NumberOfStreams
Definition: Minidump.h:37
constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION
Definition: Optional.h:266
An efficient, type-erasing, non-owning reference to a callable.
Definition: STLExtras.h:104
ArrayRef< uint8_t > arrayRefFromStringRef(StringRef Input)
Construct a string ref from an array ref of unsigned chars.
Definition: StringExtras.h:60
minidump::Header Header
The minidump header.
Definition: MinidumpYAML.h:172
ArrayRef< T > makeArrayRef(const T &OneElt)
Construct an ArrayRef from a single element.
Definition: ArrayRef.h:450
support::ulittle32_t StreamDirectoryRVA
Definition: Minidump.h:38
bool convertUTF8ToUTF16String(StringRef SrcUTF8, SmallVectorImpl< UTF16 > &DstUTF16)
Converts a UTF-8 string into a UTF-16 string with native endianness.
The top level structure representing a minidump object, consisting of a minidump header, and zero or more streams.
Definition: MinidumpYAML.h:160
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Definition: ArrayRef.h:290
detail::packed_endian_specific_integral< uint32_t, little, unaligned > ulittle32_t
Definition: Endian.h:274
Allocate memory in an ever growing pool, as if by bump-pointer.
Definition: Allocator.h:140
Instrumentation for Order File
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:148
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
void writeAsBinary(raw_ostream &OS) const
Write the contents (regardless of whether it is binary or a hex string) as binary to the given raw_os...
Definition: YAML.cpp:40
A stream representing a list of abstract entries in a minidump stream.
Definition: MinidumpYAML.h:59
StringRef toStringRef(bool B)
Construct a string ref from a boolean.
Definition: StringExtras.h:52
size_t size() const
Definition: SmallVector.h:52
const T * data() const
Definition: ArrayRef.h:145
ArrayRef< uint8_t >::size_type binary_size() const
The number of bytes that are represented by this BinaryRef.
Definition: YAML.h:80
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
The base class for all minidump streams.
Definition: MinidumpYAML.h:27
This is a &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:837
This class represents a YAML stream potentially containing multiple documents.
Definition: YAMLParser.h:83
Common declarations for yaml2obj.
std::vector< std::unique_ptr< Stream > > Streams
The list of streams in this minidump object.
Definition: MinidumpYAML.h:175
A minidump stream represented as a sequence of hex bytes.
Definition: MinidumpYAML.h:107
LocationDescriptor Location
Definition: Minidump.h:75
bool yaml2minidump(MinidumpYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH)
A range adaptor for a pair of iterators.
support::ulittle32_t RVA
Definition: Minidump.h:58
Specialized YAMLIO scalar type for representing a binary blob.
Definition: YAML.h:63
support::ulittle32_t DataSize
Definition: Minidump.h:57
static LocationDescriptor layout(BlobAllocator &File, yaml::BinaryRef Data)
Specifies the location and type of a single stream in the minidump file.
Definition: Minidump.h:73
uint32_t Size
Definition: Profile.cpp:46
support::ulittle32_t CSDVersionRVA
Definition: Minidump.h:126
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
IteratorT begin() const
uint64_t tell() const
tell - Return the current offset with the file.
Definition: raw_ostream.h:111
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:45
print Print MemDeps of function
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
const StreamKind Kind
Definition: MinidumpYAML.h:40
IteratorT end() const
const minidump::StreamType Type
Definition: MinidumpYAML.h:41
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
detail::enumerator< R > enumerate(R &&TheRange)
Given an input range, returns a new range whose values are are pair (A,B) such that A is the 0-based ...
Definition: STLExtras.h:1500
support::little_t< StreamType > Type
Definition: Minidump.h:74
The SystemInfo stream, containing various information about the system where this minidump was genera...
Definition: Minidump.h:114
std::vector< entry_type > Entries
Definition: MinidumpYAML.h:62