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 size_t layout(BlobAllocator &File, MinidumpYAML::ExceptionStream &S) {
122  File.allocateObject(S.MDExceptionStream);
123 
124  size_t DataEnd = File.tell();
125 
126  // Lay out the thread context data, (which is not a part of the stream).
127  // TODO: This usually (always?) matches the thread context of the
128  // corresponding thread, and may overlap memory regions as well. We could
129  // add a level of indirection to the MinidumpYAML format (like an array of
130  // Blobs that the LocationDescriptors index into) to be able to distinguish
131  // the cases where location descriptions overlap vs happen to reference
132  // identical data.
134 
135  return DataEnd;
136 }
137 
138 static void layout(BlobAllocator &File, MemoryListStream::entry_type &Range) {
139  Range.Entry.Memory = layout(File, Range.Content);
140 }
141 
142 static void layout(BlobAllocator &File, ModuleListStream::entry_type &M) {
143  M.Entry.ModuleNameRVA = File.allocateString(M.Name);
144 
145  M.Entry.CvRecord = layout(File, M.CvRecord);
146  M.Entry.MiscRecord = layout(File, M.MiscRecord);
147 }
148 
149 static void layout(BlobAllocator &File, ThreadListStream::entry_type &T) {
150  T.Entry.Stack.Memory = layout(File, T.Stack);
151  T.Entry.Context = layout(File, T.Context);
152 }
153 
154 template <typename EntryT>
155 static size_t layout(BlobAllocator &File,
157 
158  File.allocateNewObject<support::ulittle32_t>(S.Entries.size());
159  for (auto &E : S.Entries)
160  File.allocateObject(E.Entry);
161 
162  size_t DataEnd = File.tell();
163 
164  // Lay out the auxiliary data, (which is not a part of the stream).
165  DataEnd = File.tell();
166  for (auto &E : S.Entries)
167  layout(File, E);
168 
169  return DataEnd;
170 }
171 
172 static Directory layout(BlobAllocator &File, Stream &S) {
173  Directory Result;
174  Result.Type = S.Type;
175  Result.Location.RVA = File.tell();
176  Optional<size_t> DataEnd;
177  switch (S.Kind) {
178  case Stream::StreamKind::Exception:
179  DataEnd = layout(File, cast<MinidumpYAML::ExceptionStream>(S));
180  break;
181  case Stream::StreamKind::MemoryInfoList: {
182  MemoryInfoListStream &InfoList = cast<MemoryInfoListStream>(S);
183  File.allocateNewObject<minidump::MemoryInfoListHeader>(
185  InfoList.Infos.size());
186  File.allocateArray(makeArrayRef(InfoList.Infos));
187  break;
188  }
189  case Stream::StreamKind::MemoryList:
190  DataEnd = layout(File, cast<MemoryListStream>(S));
191  break;
192  case Stream::StreamKind::ModuleList:
193  DataEnd = layout(File, cast<ModuleListStream>(S));
194  break;
195  case Stream::StreamKind::RawContent: {
196  RawContentStream &Raw = cast<RawContentStream>(S);
197  File.allocateCallback(Raw.Size, [&Raw](raw_ostream &OS) {
198  Raw.Content.writeAsBinary(OS);
199  assert(Raw.Content.binary_size() <= Raw.Size);
200  OS << std::string(Raw.Size - Raw.Content.binary_size(), '\0');
201  });
202  break;
203  }
204  case Stream::StreamKind::SystemInfo: {
205  SystemInfoStream &SystemInfo = cast<SystemInfoStream>(S);
206  File.allocateObject(SystemInfo.Info);
207  // The CSD string is not a part of the stream.
208  DataEnd = File.tell();
209  SystemInfo.Info.CSDVersionRVA = File.allocateString(SystemInfo.CSDVersion);
210  break;
211  }
212  case Stream::StreamKind::TextContent:
213  File.allocateArray(arrayRefFromStringRef(cast<TextContentStream>(S).Text));
214  break;
215  case Stream::StreamKind::ThreadList:
216  DataEnd = layout(File, cast<ThreadListStream>(S));
217  break;
218  }
219  // If DataEnd is not set, we assume everything we generated is a part of the
220  // stream.
221  Result.Location.DataSize =
222  DataEnd.getValueOr(File.tell()) - Result.Location.RVA;
223  return Result;
224 }
225 
226 namespace llvm {
227 namespace yaml {
228 
230  ErrorHandler /*EH*/) {
231  BlobAllocator File;
232  File.allocateObject(Obj.Header);
233 
234  std::vector<Directory> StreamDirectory(Obj.Streams.size());
236  File.allocateArray(makeArrayRef(StreamDirectory));
237  Obj.Header.NumberOfStreams = StreamDirectory.size();
238 
239  for (auto &Stream : enumerate(Obj.Streams))
240  StreamDirectory[Stream.index()] = layout(File, *Stream.value());
241 
242  File.writeTo(Out);
243  return true;
244 }
245 
246 } // namespace yaml
247 } // namespace llvm
SystemInfo minidump stream.
Definition: MinidumpYAML.h:162
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:59
support::ulittle32_t NumberOfStreams
Definition: Minidump.h:40
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:213
ArrayRef< T > makeArrayRef(const T &OneElt)
Construct an ArrayRef from a single element.
Definition: ArrayRef.h:450
support::ulittle32_t StreamDirectoryRVA
Definition: Minidump.h:41
minidump::ExceptionStream MDExceptionStream
Definition: MinidumpYAML.h:109
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:201
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:141
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:61
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.
ExceptionStream minidump stream.
Definition: MinidumpYAML.h:108
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:216
A minidump stream represented as a sequence of hex bytes.
Definition: MinidumpYAML.h:148
LocationDescriptor Location
Definition: Minidump.h:122
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:61
Specialized YAMLIO scalar type for representing a binary blob.
Definition: YAML.h:63
support::ulittle32_t DataSize
Definition: Minidump.h:60
static LocationDescriptor layout(BlobAllocator &File, yaml::BinaryRef Data)
Specifies the location and type of a single stream in the minidump file.
Definition: Minidump.h:120
uint32_t Size
Definition: Profile.cpp:46
std::vector< minidump::MemoryInfo > Infos
Definition: MinidumpYAML.h:129
support::ulittle32_t CSDVersionRVA
Definition: Minidump.h:173
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
A structure containing the list of MemoryInfo entries comprising a MemoryInfoList stream...
Definition: MinidumpYAML.h:128
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
const StreamKind Kind
Definition: MinidumpYAML.h:42
IteratorT end() const
const minidump::StreamType Type
Definition: MinidumpYAML.h:43
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
LocationDescriptor ThreadContext
Definition: Minidump.h:247
support::little_t< StreamType > Type
Definition: Minidump.h:121
The SystemInfo stream, containing various information about the system where this minidump was genera...
Definition: Minidump.h:161
std::vector< entry_type > Entries
Definition: MinidumpYAML.h:64