LLVM  16.0.0git
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 #include <optional>
14 
15 using namespace llvm;
16 using namespace llvm::minidump;
17 using namespace llvm::MinidumpYAML;
18 
19 namespace {
20 /// A helper class to manage the placement of various structures into the final
21 /// minidump binary. Space for objects can be allocated via various allocate***
22 /// methods, while the final minidump file is written by calling the writeTo
23 /// method. The plain versions of allocation functions take a reference to the
24 /// data which is to be written (and hence the data must be available until
25 /// writeTo is called), while the "New" versions allocate the data in an
26 /// allocator-managed buffer, which is available until the allocator object is
27 /// destroyed. For both kinds of functions, it is possible to modify the
28 /// data for which the space has been "allocated" until the final writeTo call.
29 /// This is useful for "linking" the allocated structures via their offsets.
30 class BlobAllocator {
31 public:
32  size_t tell() const { return NextOffset; }
33 
34  size_t allocateCallback(size_t Size,
35  std::function<void(raw_ostream &)> Callback) {
36  size_t Offset = NextOffset;
37  NextOffset += Size;
38  Callbacks.push_back(std::move(Callback));
39  return Offset;
40  }
41 
42  size_t allocateBytes(ArrayRef<uint8_t> Data) {
43  return allocateCallback(
44  Data.size(), [Data](raw_ostream &OS) { OS << toStringRef(Data); });
45  }
46 
47  size_t allocateBytes(yaml::BinaryRef Data) {
48  return allocateCallback(Data.binary_size(), [Data](raw_ostream &OS) {
49  Data.writeAsBinary(OS);
50  });
51  }
52 
53  template <typename T> size_t allocateArray(ArrayRef<T> Data) {
54  return allocateBytes({reinterpret_cast<const uint8_t *>(Data.data()),
55  sizeof(T) * Data.size()});
56  }
57 
58  template <typename T, typename RangeType>
59  std::pair<size_t, MutableArrayRef<T>>
60  allocateNewArray(const iterator_range<RangeType> &Range);
61 
62  template <typename T> size_t allocateObject(const T &Data) {
63  return allocateArray(makeArrayRef(Data));
64  }
65 
66  template <typename T, typename... Types>
67  std::pair<size_t, T *> allocateNewObject(Types &&... Args) {
68  T *Object = new (Temporaries.Allocate<T>()) T(std::forward<Types>(Args)...);
69  return {allocateObject(*Object), Object};
70  }
71 
72  size_t allocateString(StringRef Str);
73 
74  void writeTo(raw_ostream &OS) const;
75 
76 private:
77  size_t NextOffset = 0;
78 
79  BumpPtrAllocator Temporaries;
80  std::vector<std::function<void(raw_ostream &)>> Callbacks;
81 };
82 } // namespace
83 
84 template <typename T, typename RangeType>
85 std::pair<size_t, MutableArrayRef<T>>
86 BlobAllocator::allocateNewArray(const iterator_range<RangeType> &Range) {
87  size_t Num = std::distance(Range.begin(), Range.end());
88  MutableArrayRef<T> Array(Temporaries.Allocate<T>(Num), Num);
89  std::uninitialized_copy(Range.begin(), Range.end(), Array.begin());
90  return {allocateArray(Array), Array};
91 }
92 
93 size_t BlobAllocator::allocateString(StringRef Str) {
95  bool OK = convertUTF8ToUTF16String(Str, WStr);
96  assert(OK && "Invalid UTF8 in Str?");
97  (void)OK;
98 
99  // The utf16 string is null-terminated, but the terminator is not counted in
100  // the string size.
101  WStr.push_back(0);
102  size_t Result =
103  allocateNewObject<support::ulittle32_t>(2 * (WStr.size() - 1)).first;
104  allocateNewArray<support::ulittle16_t>(make_range(WStr.begin(), WStr.end()));
105  return Result;
106 }
107 
108 void BlobAllocator::writeTo(raw_ostream &OS) const {
109  size_t BeginOffset = OS.tell();
110  for (const auto &Callback : Callbacks)
111  Callback(OS);
112  assert(OS.tell() == BeginOffset + NextOffset &&
113  "Callbacks wrote an unexpected number of bytes.");
114  (void)BeginOffset;
115 }
116 
117 static LocationDescriptor layout(BlobAllocator &File, yaml::BinaryRef Data) {
118  return {support::ulittle32_t(Data.binary_size()),
119  support::ulittle32_t(File.allocateBytes(Data))};
120 }
121 
122 static size_t layout(BlobAllocator &File, MinidumpYAML::ExceptionStream &S) {
123  File.allocateObject(S.MDExceptionStream);
124 
125  size_t DataEnd = File.tell();
126 
127  // Lay out the thread context data, (which is not a part of the stream).
128  // TODO: This usually (always?) matches the thread context of the
129  // corresponding thread, and may overlap memory regions as well. We could
130  // add a level of indirection to the MinidumpYAML format (like an array of
131  // Blobs that the LocationDescriptors index into) to be able to distinguish
132  // the cases where location descriptions overlap vs happen to reference
133  // identical data.
134  S.MDExceptionStream.ThreadContext = layout(File, S.ThreadContext);
135 
136  return DataEnd;
137 }
138 
139 static void layout(BlobAllocator &File, MemoryListStream::entry_type &Range) {
140  Range.Entry.Memory = layout(File, Range.Content);
141 }
142 
143 static void layout(BlobAllocator &File, ModuleListStream::entry_type &M) {
144  M.Entry.ModuleNameRVA = File.allocateString(M.Name);
145 
146  M.Entry.CvRecord = layout(File, M.CvRecord);
147  M.Entry.MiscRecord = layout(File, M.MiscRecord);
148 }
149 
150 static void layout(BlobAllocator &File, ThreadListStream::entry_type &T) {
151  T.Entry.Stack.Memory = layout(File, T.Stack);
152  T.Entry.Context = layout(File, T.Context);
153 }
154 
155 template <typename EntryT>
156 static size_t layout(BlobAllocator &File,
158 
159  File.allocateNewObject<support::ulittle32_t>(S.Entries.size());
160  for (auto &E : S.Entries)
161  File.allocateObject(E.Entry);
162 
163  size_t DataEnd = File.tell();
164 
165  // Lay out the auxiliary data, (which is not a part of the stream).
166  DataEnd = File.tell();
167  for (auto &E : S.Entries)
168  layout(File, E);
169 
170  return DataEnd;
171 }
172 
173 static Directory layout(BlobAllocator &File, Stream &S) {
174  Directory Result;
175  Result.Type = S.Type;
176  Result.Location.RVA = File.tell();
177  std::optional<size_t> DataEnd;
178  switch (S.Kind) {
179  case Stream::StreamKind::Exception:
180  DataEnd = layout(File, cast<MinidumpYAML::ExceptionStream>(S));
181  break;
182  case Stream::StreamKind::MemoryInfoList: {
183  MemoryInfoListStream &InfoList = cast<MemoryInfoListStream>(S);
184  File.allocateNewObject<minidump::MemoryInfoListHeader>(
186  InfoList.Infos.size());
187  File.allocateArray(makeArrayRef(InfoList.Infos));
188  break;
189  }
190  case Stream::StreamKind::MemoryList:
191  DataEnd = layout(File, cast<MemoryListStream>(S));
192  break;
193  case Stream::StreamKind::ModuleList:
194  DataEnd = layout(File, cast<ModuleListStream>(S));
195  break;
196  case Stream::StreamKind::RawContent: {
197  RawContentStream &Raw = cast<RawContentStream>(S);
198  File.allocateCallback(Raw.Size, [&Raw](raw_ostream &OS) {
199  Raw.Content.writeAsBinary(OS);
200  assert(Raw.Content.binary_size() <= Raw.Size);
201  OS << std::string(Raw.Size - Raw.Content.binary_size(), '\0');
202  });
203  break;
204  }
205  case Stream::StreamKind::SystemInfo: {
206  SystemInfoStream &SystemInfo = cast<SystemInfoStream>(S);
207  File.allocateObject(SystemInfo.Info);
208  // The CSD string is not a part of the stream.
209  DataEnd = File.tell();
210  SystemInfo.Info.CSDVersionRVA = File.allocateString(SystemInfo.CSDVersion);
211  break;
212  }
213  case Stream::StreamKind::TextContent:
214  File.allocateArray(arrayRefFromStringRef(cast<TextContentStream>(S).Text));
215  break;
216  case Stream::StreamKind::ThreadList:
217  DataEnd = layout(File, cast<ThreadListStream>(S));
218  break;
219  }
220  // If DataEnd is not set, we assume everything we generated is a part of the
221  // stream.
222  Result.Location.DataSize =
223  DataEnd.value_or(File.tell()) - Result.Location.RVA;
224  return Result;
225 }
226 
227 namespace llvm {
228 namespace yaml {
229 
231  ErrorHandler /*EH*/) {
232  BlobAllocator File;
233  File.allocateObject(Obj.Header);
234 
235  std::vector<Directory> StreamDirectory(Obj.Streams.size());
237  File.allocateArray(makeArrayRef(StreamDirectory));
238  Obj.Header.NumberOfStreams = StreamDirectory.size();
239 
240  for (auto &Stream : enumerate(Obj.Streams))
241  StreamDirectory[Stream.index()] = layout(File, *Stream.value());
242 
243  File.writeTo(Out);
244  return true;
245 }
246 
247 } // namespace yaml
248 } // namespace llvm
llvm::Check::Size
@ Size
Definition: FileCheck.h:77
llvm::minidump::MemoryInfoListHeader
Definition: Minidump.h:73
llvm::raw_ostream::tell
uint64_t tell() const
tell - Return the current offset with the file.
Definition: raw_ostream.h:135
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
M
We currently emits eax Perhaps this is what we really should generate is Is imull three or four cycles eax eax The current instruction priority is based on pattern complexity The former is more complex because it folds a load so the latter will not be emitted Perhaps we should use AddedComplexity to give LEA32r a higher priority We should always try to match LEA first since the LEA matching code does some estimate to determine whether the match is profitable if we care more about code then imull is better It s two bytes shorter than movl leal On a Pentium M
Definition: README.txt:252
llvm::make_range
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
Definition: iterator_range.h:53
llvm::support::detail::packed_endian_specific_integral
Definition: Endian.h:206
T
llvm::MinidumpYAML::Object
The top level structure representing a minidump object, consisting of a minidump header,...
Definition: MinidumpYAML.h:201
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1199
layout
static LocationDescriptor layout(BlobAllocator &File, yaml::BinaryRef Data)
Definition: MinidumpEmitter.cpp:117
llvm::enumerate
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:2263
llvm::minidump::MemoryInfo
Definition: Minidump.h:104
llvm::msgpack::Type::Array
@ Array
llvm::minidump::LocationDescriptor
Specifies the location (and size) of various objects in the minidump file.
Definition: Minidump.h:59
llvm::Data
@ Data
Definition: SIMachineScheduler.h:55
llvm::minidump::SystemInfo
The SystemInfo stream, containing various information about the system where this minidump was genera...
Definition: Minidump.h:161
llvm::MinidumpYAML::detail::ListStream
A stream representing a list of abstract entries in a minidump stream.
Definition: MinidumpYAML.h:61
llvm::MutableArrayRef
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Definition: ArrayRef.h:28
E
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
MinidumpYAML.h
llvm::MinidumpYAML::Object::Header
minidump::Header Header
The minidump header.
Definition: MinidumpYAML.h:213
llvm::ms_demangle::QualifierMangleMode::Result
@ Result
llvm::MinidumpYAML::Object::Streams
std::vector< std::unique_ptr< Stream > > Streams
The list of streams in this minidump object.
Definition: MinidumpYAML.h:216
llvm::raw_ostream
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
llvm::function_ref
An efficient, type-erasing, non-owning reference to a callable.
Definition: STLFunctionalExtras.h:36
llvm::support::ulittle32_t
detail::packed_endian_specific_integral< uint32_t, little, unaligned > ulittle32_t
Definition: Endian.h:272
llvm::AMDGPU::Hwreg::Offset
Offset
Definition: SIDefines.h:416
llvm::BumpPtrAllocatorImpl
Allocate memory in an ever growing pool, as if by bump-pointer.
Definition: Allocator.h:63
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
llvm::MinidumpYAML::RawContentStream::Size
yaml::Hex32 Size
Definition: MinidumpYAML.h:150
llvm::MinidumpYAML
Definition: MinidumpYAML.h:18
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
function
print Print MemDeps of function
Definition: MemDepPrinter.cpp:82
llvm::MinidumpYAML::Stream
The base class for all minidump streams.
Definition: MinidumpYAML.h:27
llvm::MinidumpYAML::SystemInfoStream
SystemInfo minidump stream.
Definition: MinidumpYAML.h:162
yaml2obj.h
llvm::ArrayRef< uint8_t >
llvm::logicalview::LVCompareKind::Types
@ Types
llvm::MinidumpYAML::MemoryInfoListStream::Infos
std::vector< minidump::MemoryInfo > Infos
Definition: MinidumpYAML.h:129
llvm::logicalview::LVAttributeKind::Range
@ Range
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
llvm::yaml::BinaryRef
Specialized YAMLIO scalar type for representing a binary blob.
Definition: YAML.h:63
llvm::minidump
Definition: Minidump.h:26
llvm::yaml::Stream
This class represents a YAML stream potentially containing multiple documents.
Definition: YAMLParser.h:85
S
add sub stmia L5 ldr r0 bl L_printf $stub Instead of a and a wouldn t it be better to do three moves *Return an aggregate type is even return S
Definition: README.txt:210
ConvertUTF.h
llvm::convertUTF8ToUTF16String
bool convertUTF8ToUTF16String(StringRef SrcUTF8, SmallVectorImpl< UTF16 > &DstUTF16)
Converts a UTF-8 string into a UTF-16 string with native endianness.
Definition: ConvertUTFWrapper.cpp:200
llvm::minidump::Directory
Specifies the location and type of a single stream in the minidump file.
Definition: Minidump.h:120
llvm::yaml::yaml2minidump
bool yaml2minidump(MinidumpYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH)
Definition: MinidumpEmitter.cpp:230
llvm::makeArrayRef
ArrayRef< T > makeArrayRef(const T &OneElt)
Construct an ArrayRef from a single element.
Definition: ArrayRef.h:475
llvm::MinidumpYAML::ExceptionStream
ExceptionStream minidump stream.
Definition: MinidumpYAML.h:108
llvm::MinidumpYAML::RawContentStream
A minidump stream represented as a sequence of hex bytes.
Definition: MinidumpYAML.h:148
llvm::iterator_range
A range adaptor for a pair of iterators.
Definition: iterator_range.h:30
llvm::minidump::SystemInfo::CSDVersionRVA
support::ulittle32_t CSDVersionRVA
Definition: Minidump.h:173
llvm::AMDGPU::HSAMD::Kernel::Key::Args
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
Definition: AMDGPUMetadata.h:394
llvm::ARMBuildAttrs::File
@ File
Definition: ARMBuildAttributes.h:36
raw_ostream.h
llvm::MinidumpYAML::MemoryInfoListStream
A structure containing the list of MemoryInfo entries comprising a MemoryInfoList stream.
Definition: MinidumpYAML.h:128
llvm::MinidumpYAML::detail::ListStream::entry_type
EntryT entry_type
Definition: MinidumpYAML.h:62
llvm::minidump::Header::StreamDirectoryRVA
support::ulittle32_t StreamDirectoryRVA
Definition: Minidump.h:41
llvm::minidump::Header::NumberOfStreams
support::ulittle32_t NumberOfStreams
Definition: Minidump.h:40