llvm.org GIT mirror llvm / 2385b8e
[ObjectYAML] Add basic minidump generation support Summary: This patch adds the ability to read a yaml form of a minidump file and write it out as binary. Apart from the minidump header and the stream directory, only three basic stream kinds are supported: - Text: This kind is used for streams which contain textual data. This is typically the contents of a /proc file on linux (e.g. /proc/PID/maps). In this case, we just put the raw stream contents into the yaml. - SystemInfo: This stream contains various bits of information about the host system in binary form. We expose the data in a structured form. - Raw: This kind is used as a fallback when we don't have any special knowledge about the stream. In this case, we just print the stream contents in hex. For this code to be really useful, more stream kinds will need to be added (particularly for things like lists of memory regions and loaded modules). However, these can be added incrementally. Reviewers: jhenderson, zturner, clayborg, aprantl Subscribers: mgorny, lemo, llvm-commits, lldb-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D59482 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@356753 91177308-0d34-0410-b5e6-96231b3b80d8 Pavel Labath 5 months ago
17 changed file(s) with 795 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 //===- MinidumpYAML.h - Minidump YAMLIO implementation ----------*- C++ -*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7
8 #ifndef LLVM_OBJECTYAML_MINIDUMPYAML_H
9 #define LLVM_OBJECTYAML_MINIDUMPYAML_H
10
11 #include "llvm/BinaryFormat/Minidump.h"
12 #include "llvm/ObjectYAML/YAML.h"
13 #include "llvm/Support/YAMLTraits.h"
14
15 namespace llvm {
16 namespace MinidumpYAML {
17
18 /// The base class for all minidump streams. The "Type" of the stream
19 /// corresponds to the Stream Type field in the minidump file. The "Kind" field
20 /// specifies how are we going to treat it. For highly specialized streams (e.g.
21 /// SystemInfo), there is a 1:1 mapping between Types and Kinds, but in general
22 /// one stream Kind can be used to represent multiple stream Types (e.g. any
23 /// unrecognised stream Type will be handled via RawContentStream). The mapping
24 /// from Types to Kinds is fixed and given by the static getKind function.
25 struct Stream {
26 enum class StreamKind {
27 RawContent,
28 SystemInfo,
29 TextContent,
30 };
31
32 Stream(StreamKind Kind, minidump::StreamType Type) : Kind(Kind), Type(Type) {}
33 virtual ~Stream(); // anchor
34
35 const StreamKind Kind;
36 const minidump::StreamType Type;
37
38 /// Get the stream Kind used for representing streams of a given Type.
39 static StreamKind getKind(minidump::StreamType Type);
40
41 /// Create an empty stream of the given Type.
42 static std::unique_ptr create(minidump::StreamType Type);
43 };
44
45 /// A minidump stream represented as a sequence of hex bytes. This is used as a
46 /// fallback when no other stream kind is suitable.
47 struct RawContentStream : public Stream {
48 yaml::BinaryRef Content;
49 yaml::Hex32 Size;
50
51 RawContentStream(minidump::StreamType Type, ArrayRef Content = {})
52 : Stream(StreamKind::RawContent, Type), Content(Content),
53 Size(Content.size()) {}
54
55 static bool classof(const Stream *S) {
56 return S->Kind == StreamKind::RawContent;
57 }
58 };
59
60 /// SystemInfo minidump stream.
61 struct SystemInfoStream : public Stream {
62 minidump::SystemInfo Info;
63
64 explicit SystemInfoStream(const minidump::SystemInfo &Info)
65 : Stream(StreamKind::SystemInfo, minidump::StreamType::SystemInfo),
66 Info(Info) {}
67
68 SystemInfoStream()
69 : Stream(StreamKind::SystemInfo, minidump::StreamType::SystemInfo) {
70 memset(&Info, 0, sizeof(Info));
71 }
72
73 static bool classof(const Stream *S) {
74 return S->Kind == StreamKind::SystemInfo;
75 }
76 };
77
78 /// A StringRef, which is printed using YAML block notation.
79 LLVM_YAML_STRONG_TYPEDEF(StringRef, BlockStringRef)
80
81 /// A minidump stream containing textual data (typically, the contents of a
82 /// /proc/ file on linux).
83 struct TextContentStream : public Stream {
84 BlockStringRef Text;
85
86 TextContentStream(minidump::StreamType Type, StringRef Text = {})
87 : Stream(StreamKind::TextContent, Type), Text(Text) {}
88
89 static bool classof(const Stream *S) {
90 return S->Kind == StreamKind::TextContent;
91 }
92 };
93
94 /// The top level structure representing a minidump object, consisting of a
95 /// minidump header, and zero or more streams. To construct an Object from a
96 /// minidump file, use the static create function. To serialize to/from yaml,
97 /// use the appropriate streaming operator on a yaml stream.
98 struct Object {
99 Object() = default;
100 Object(const Object &) = delete;
101 Object &operator=(const Object &) = delete;
102 Object(Object &&) = default;
103 Object &operator=(Object &&) = default;
104
105 /// The minidump header.
106 minidump::Header Header;
107
108 /// The list of streams in this minidump object.
109 std::vector> Streams;
110 };
111
112 /// Serialize the minidump file represented by Obj to OS in binary form.
113 void writeAsBinary(Object &Obj, raw_ostream &OS);
114
115 /// Serialize the yaml string as a minidump file to OS in binary form.
116 Error writeAsBinary(StringRef Yaml, raw_ostream &OS);
117
118 } // namespace MinidumpYAML
119
120 namespace yaml {
121 template <> struct BlockScalarTraits {
122 static void output(const MinidumpYAML::BlockStringRef &Text, void *,
123 raw_ostream &OS) {
124 OS << Text;
125 }
126
127 static StringRef input(StringRef Scalar, void *,
128 MinidumpYAML::BlockStringRef &Text) {
129 Text = Scalar;
130 return "";
131 }
132 };
133
134 template <> struct MappingTraits> {
135 static void mapping(IO &IO, std::unique_ptr &S);
136 static StringRef validate(IO &IO, std::unique_ptr &S);
137 };
138
139 } // namespace yaml
140
141 } // namespace llvm
142
143 LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::ProcessorArchitecture)
144 LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::OSPlatform)
145 LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::StreamType)
146
147 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::ArmInfo)
148 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::OtherInfo)
149 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::X86Info)
150
151 LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr)
152
153 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::MinidumpYAML::Object)
154
155 #endif // LLVM_OBJECTYAML_MINIDUMPYAML_H
1111 #include "llvm/ObjectYAML/COFFYAML.h"
1212 #include "llvm/ObjectYAML/ELFYAML.h"
1313 #include "llvm/ObjectYAML/MachOYAML.h"
14 #include "llvm/ObjectYAML/MinidumpYAML.h"
1415 #include "llvm/ObjectYAML/WasmYAML.h"
1516 #include "llvm/Support/YAMLTraits.h"
1617 #include
2526 std::unique_ptr Coff;
2627 std::unique_ptr MachO;
2728 std::unique_ptr FatMachO;
29 std::unique_ptr Minidump;
2830 std::unique_ptr Wasm;
2931 };
3032
99 ELFYAML.cpp
1010 MachOYAML.cpp
1111 ObjectYAML.cpp
12 MinidumpYAML.cpp
1213 WasmYAML.cpp
1314 YAML.cpp
1415 )
0 //===- MinidumpYAML.cpp - Minidump YAMLIO implementation ------------------===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7
8 #include "llvm/ObjectYAML/MinidumpYAML.h"
9
10 using namespace llvm;
11 using namespace llvm::MinidumpYAML;
12 using namespace llvm::minidump;
13
14 namespace {
15 class BlobAllocator {
16 public:
17 size_t tell() const { return NextOffset; }
18
19 size_t AllocateCallback(size_t Size,
20 std::function Callback) {
21 size_t Offset = NextOffset;
22 NextOffset += Size;
23 Callbacks.push_back(std::move(Callback));
24 return Offset;
25 }
26
27 size_t AllocateBytes(ArrayRef Data) {
28 return AllocateCallback(
29 Data.size(), [Data](raw_ostream &OS) { OS << toStringRef(Data); });
30 }
31
32 template size_t AllocateArray(ArrayRef Data) {
33 return AllocateBytes({reinterpret_cast(Data.data()),
34 sizeof(T) * Data.size()});
35 }
36
37 template size_t AllocateObject(const T &Data) {
38 return AllocateArray(makeArrayRef(Data));
39 }
40
41 void writeTo(raw_ostream &OS) const;
42
43 private:
44 size_t NextOffset = 0;
45
46 std::vector> Callbacks;
47 };
48 } // namespace
49
50 void BlobAllocator::writeTo(raw_ostream &OS) const {
51 size_t BeginOffset = OS.tell();
52 for (const auto &Callback : Callbacks)
53 Callback(OS);
54 assert(OS.tell() == BeginOffset + NextOffset &&
55 "Callbacks wrote an unexpected number of bytes.");
56 (void)BeginOffset;
57 }
58
59 /// Perform an optional yaml-mapping of an endian-aware type EndianType. The
60 /// only purpose of this function is to avoid casting the Default value to the
61 /// endian type;
62 template
63 static inline void mapOptional(yaml::IO &IO, const char *Key, EndianType &Val,
64 typename EndianType::value_type Default) {
65 IO.mapOptional(Key, Val, EndianType(Default));
66 }
67
68 /// Yaml-map an endian-aware type EndianType as some other type MapType.
69 template
70 static inline void mapRequiredAs(yaml::IO &IO, const char *Key,
71 EndianType &Val) {
72 MapType Mapped = static_cast(Val);
73 IO.mapRequired(Key, Mapped);
74 Val = static_cast(Mapped);
75 }
76
77 /// Perform an optional yaml-mapping of an endian-aware type EndianType as some
78 /// other type MapType.
79 template
80 static inline void mapOptionalAs(yaml::IO &IO, const char *Key, EndianType &Val,
81 MapType Default) {
82 MapType Mapped = static_cast(Val);
83 IO.mapOptional(Key, Mapped, Default);
84 Val = static_cast(Mapped);
85 }
86
87 namespace {
88 /// Return the appropriate yaml Hex type for a given endian-aware type.
89 template struct HexType;
90 template <> struct HexType { using type = yaml::Hex16; };
91 template <> struct HexType { using type = yaml::Hex32; };
92 template <> struct HexType { using type = yaml::Hex64; };
93 } // namespace
94
95 /// Yaml-map an endian-aware type as an appropriately-sized hex value.
96 template
97 static inline void mapRequiredHex(yaml::IO &IO, const char *Key,
98 EndianType &Val) {
99 mapRequiredAs::type>(IO, Key, Val);
100 }
101
102 /// Perform an optional yaml-mapping of an endian-aware type as an
103 /// appropriately-sized hex value.
104 template
105 static inline void mapOptionalHex(yaml::IO &IO, const char *Key,
106 EndianType &Val,
107 typename EndianType::value_type Default) {
108 mapOptionalAs::type>(IO, Key, Val, Default);
109 }
110
111 Stream::~Stream() = default;
112
113 Stream::StreamKind Stream::getKind(StreamType Type) {
114 switch (Type) {
115 case StreamType::SystemInfo:
116 return StreamKind::SystemInfo;
117 case StreamType::LinuxCPUInfo:
118 case StreamType::LinuxProcStatus:
119 case StreamType::LinuxLSBRelease:
120 case StreamType::LinuxCMDLine:
121 case StreamType::LinuxMaps:
122 case StreamType::LinuxProcStat:
123 case StreamType::LinuxProcUptime:
124 return StreamKind::TextContent;
125 default:
126 return StreamKind::RawContent;
127 }
128 }
129
130 std::unique_ptr Stream::create(StreamType Type) {
131 StreamKind Kind = getKind(Type);
132 switch (Kind) {
133 case StreamKind::RawContent:
134 return llvm::make_unique(Type);
135 case StreamKind::SystemInfo:
136 return llvm::make_unique();
137 case StreamKind::TextContent:
138 return llvm::make_unique(Type);
139 }
140 llvm_unreachable("Unhandled stream kind!");
141 }
142
143 void yaml::ScalarEnumerationTraits::enumeration(
144 IO &IO, ProcessorArchitecture &Arch) {
145 #define HANDLE_MDMP_ARCH(CODE, NAME) \
146 IO.enumCase(Arch, #NAME, ProcessorArchitecture::NAME);
147 #include "llvm/BinaryFormat/MinidumpConstants.def"
148 IO.enumFallback(Arch);
149 }
150
151 void yaml::ScalarEnumerationTraits::enumeration(IO &IO,
152 OSPlatform &Plat) {
153 #define HANDLE_MDMP_PLATFORM(CODE, NAME) \
154 IO.enumCase(Plat, #NAME, OSPlatform::NAME);
155 #include "llvm/BinaryFormat/MinidumpConstants.def"
156 IO.enumFallback(Plat);
157 }
158
159 void yaml::ScalarEnumerationTraits::enumeration(IO &IO,
160 StreamType &Type) {
161 #define HANDLE_MDMP_STREAM_TYPE(CODE, NAME) \
162 IO.enumCase(Type, #NAME, StreamType::NAME);
163 #include "llvm/BinaryFormat/MinidumpConstants.def"
164 IO.enumFallback(Type);
165 }
166
167 void yaml::MappingTraits::mapping(IO &IO,
168 CPUInfo::ArmInfo &Info) {
169 mapRequiredHex(IO, "CPUID", Info.CPUID);
170 mapOptionalHex(IO, "ELF hwcaps", Info.ElfHWCaps, 0);
171 }
172
173 namespace {
174 template struct FixedSizeHex {
175 FixedSizeHex(uint8_t (&Storage)[N]) : Storage(Storage) {}
176
177 uint8_t (&Storage)[N];
178 };
179 } // namespace
180
181 namespace llvm {
182 namespace yaml {
183 template struct ScalarTraits> {
184 static void output(const FixedSizeHex &Fixed, void *, raw_ostream &OS) {
185 OS << toHex(makeArrayRef(Fixed.Storage));
186 }
187
188 static StringRef input(StringRef Scalar, void *, FixedSizeHex &Fixed) {
189 if (!all_of(Scalar, isHexDigit))
190 return "Invalid hex digit in input";
191 if (Scalar.size() < 2 * N)
192 return "String too short";
193 if (Scalar.size() > 2 * N)
194 return "String too long";
195 copy(fromHex(Scalar), Fixed.Storage);
196 return "";
197 }
198
199 static QuotingType mustQuote(StringRef S) { return QuotingType::None; }
200 };
201 } // namespace yaml
202 } // namespace llvm
203 void yaml::MappingTraits::mapping(
204 IO &IO, CPUInfo::OtherInfo &Info) {
205 FixedSizeHex Features(Info.ProcessorFeatures);
206 IO.mapRequired("Features", Features);
207 }
208
209 namespace {
210 /// A type which only accepts strings of a fixed size for yaml conversion.
211 template struct FixedSizeString {
212 FixedSizeString(char (&Storage)[N]) : Storage(Storage) {}
213
214 char (&Storage)[N];
215 };
216 } // namespace
217
218 namespace llvm {
219 namespace yaml {
220 template struct ScalarTraits> {
221 static void output(const FixedSizeString &Fixed, void *, raw_ostream &OS) {
222 OS << StringRef(Fixed.Storage, N);
223 }
224
225 static StringRef input(StringRef Scalar, void *, FixedSizeString &Fixed) {
226 if (Scalar.size() < N)
227 return "String too short";
228 if (Scalar.size() > N)
229 return "String too long";
230 copy(Scalar, Fixed.Storage);
231 return "";
232 }
233
234 static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
235 };
236 } // namespace yaml
237 } // namespace llvm
238
239 void yaml::MappingTraits::mapping(IO &IO,
240 CPUInfo::X86Info &Info) {
241 FixedSizeString VendorID(Info.VendorID);
242 IO.mapRequired("Vendor ID", VendorID);
243
244 mapRequiredHex(IO, "Version Info", Info.VersionInfo);
245 mapRequiredHex(IO, "Feature Info", Info.FeatureInfo);
246 mapOptionalHex(IO, "AMD Extended Features", Info.AMDExtendedFeatures, 0);
247 }
248
249 static void streamMapping(yaml::IO &IO, RawContentStream &Stream) {
250 IO.mapOptional("Content", Stream.Content);
251 IO.mapOptional("Size", Stream.Size, Stream.Content.binary_size());
252 }
253
254 static StringRef streamValidate(RawContentStream &Stream) {
255 if (Stream.Size.value < Stream.Content.binary_size())
256 return "Stream size must be greater or equal to the content size";
257 return "";
258 }
259
260 static void streamMapping(yaml::IO &IO, SystemInfoStream &Stream) {
261 SystemInfo &Info = Stream.Info;
262 IO.mapRequired("Processor Arch", Info.ProcessorArch);
263 mapOptional(IO, "Processor Level", Info.ProcessorLevel, 0);
264 mapOptional(IO, "Processor Revision", Info.ProcessorRevision, 0);
265 IO.mapOptional("Number of Processors", Info.NumberOfProcessors, 0);
266 IO.mapOptional("Product type", Info.ProductType, 0);
267 mapOptional(IO, "Major Version", Info.MajorVersion, 0);
268 mapOptional(IO, "Minor Version", Info.MinorVersion, 0);
269 mapOptional(IO, "Build Number", Info.BuildNumber, 0);
270 IO.mapRequired("Platform ID", Info.PlatformId);
271 mapOptionalHex(IO, "CSD Version RVA", Info.CSDVersionRVA, 0);
272 mapOptionalHex(IO, "Suite Mask", Info.SuiteMask, 0);
273 mapOptionalHex(IO, "Reserved", Info.Reserved, 0);
274 switch (static_cast(Info.ProcessorArch)) {
275 case ProcessorArchitecture::X86:
276 case ProcessorArchitecture::AMD64:
277 IO.mapOptional("CPU", Info.CPU.X86);
278 break;
279 case ProcessorArchitecture::ARM:
280 case ProcessorArchitecture::ARM64:
281 IO.mapOptional("CPU", Info.CPU.Arm);
282 break;
283 default:
284 IO.mapOptional("CPU", Info.CPU.Other);
285 break;
286 }
287 }
288
289 static void streamMapping(yaml::IO &IO, TextContentStream &Stream) {
290 IO.mapOptional("Text", Stream.Text);
291 }
292
293 void yaml::MappingTraits>::mapping(
294 yaml::IO &IO, std::unique_ptr &S) {
295 StreamType Type;
296 if (IO.outputting())
297 Type = S->Type;
298 IO.mapRequired("Type", Type);
299
300 if (!IO.outputting())
301 S = MinidumpYAML::Stream::create(Type);
302 switch (S->Kind) {
303 case MinidumpYAML::Stream::StreamKind::RawContent:
304 streamMapping(IO, llvm::cast(*S));
305 break;
306 case MinidumpYAML::Stream::StreamKind::SystemInfo:
307 streamMapping(IO, llvm::cast(*S));
308 break;
309 case MinidumpYAML::Stream::StreamKind::TextContent:
310 streamMapping(IO, llvm::cast(*S));
311 break;
312 }
313 }
314
315 StringRef yaml::MappingTraits>::validate(
316 yaml::IO &IO, std::unique_ptr &S) {
317 switch (S->Kind) {
318 case MinidumpYAML::Stream::StreamKind::RawContent:
319 return streamValidate(cast(*S));
320 case MinidumpYAML::Stream::StreamKind::SystemInfo:
321 case MinidumpYAML::Stream::StreamKind::TextContent:
322 return "";
323 }
324 llvm_unreachable("Fully covered switch above!");
325 }
326
327 void yaml::MappingTraits::mapping(IO &IO, Object &O) {
328 IO.mapTag("!minidump", true);
329 mapOptionalHex(IO, "Signature", O.Header.Signature, Header::MagicSignature);
330 mapOptionalHex(IO, "Version", O.Header.Version, Header::MagicVersion);
331 mapOptionalHex(IO, "Flags", O.Header.Flags, 0);
332 IO.mapRequired("Streams", O.Streams);
333 }
334
335 static Directory layout(BlobAllocator &File, Stream &S) {
336 Directory Result;
337 Result.Type = S.Type;
338 Result.Location.RVA = File.tell();
339 switch (S.Kind) {
340 case Stream::StreamKind::RawContent: {
341 RawContentStream &Raw = cast(S);
342 File.AllocateCallback(Raw.Size, [&Raw](raw_ostream &OS) {
343 Raw.Content.writeAsBinary(OS);
344 assert(Raw.Content.binary_size() <= Raw.Size);
345 OS << std::string(Raw.Size - Raw.Content.binary_size(), '\0');
346 });
347 break;
348 }
349 case Stream::StreamKind::SystemInfo:
350 File.AllocateObject(cast(S).Info);
351 break;
352 case Stream::StreamKind::TextContent:
353 File.AllocateArray(arrayRefFromStringRef(cast(S).Text));
354 break;
355 }
356 Result.Location.DataSize = File.tell() - Result.Location.RVA;
357 return Result;
358 }
359
360 void MinidumpYAML::writeAsBinary(Object &Obj, raw_ostream &OS) {
361 BlobAllocator File;
362 File.AllocateObject(Obj.Header);
363
364 std::vector StreamDirectory(Obj.Streams.size());
365 Obj.Header.StreamDirectoryRVA =
366 File.AllocateArray(makeArrayRef(StreamDirectory));
367 Obj.Header.NumberOfStreams = StreamDirectory.size();
368
369 for (auto &Stream : enumerate(Obj.Streams))
370 StreamDirectory[Stream.index()] = layout(File, *Stream.value());
371
372 File.writeTo(OS);
373 }
374
375 Error MinidumpYAML::writeAsBinary(StringRef Yaml, raw_ostream &OS) {
376 yaml::Input Input(Yaml);
377 Object Obj;
378 Input >> Obj;
379 if (std::error_code EC = Input.error())
380 return errorCodeToError(EC);
381
382 writeAsBinary(Obj, OS);
383 return Error::success();
384 }
4444 ObjectFile.FatMachO.reset(new MachOYAML::UniversalBinary());
4545 MappingTraits::mapping(IO,
4646 *ObjectFile.FatMachO);
47 } else if (IO.mapTag("!minidump")) {
48 ObjectFile.Minidump.reset(new MinidumpYAML::Object());
49 MappingTraits::mapping(IO, *ObjectFile.Minidump);
4750 } else if (IO.mapTag("!WASM")) {
4851 ObjectFile.Wasm.reset(new WasmYAML::Object());
4952 MappingTraits::mapping(IO, *ObjectFile.Wasm);
0 # RUN: not yaml2obj %s 2>&1 | FileCheck %s
1
2 --- !minidump
3 Streams:
4 - Type: LinuxAuxv
5 Size: 7
6 Content: DEADBEEFBAADF00D
7
8 # CHECK: Stream size must be greater or equal to the content size
0 # RUN: not yaml2obj %s 2>&1 | FileCheck %s
1
2 --- !minidump
3 Streams:
4 - Type: SystemInfo
5 Processor Arch: PPC
6 Platform ID: Linux
7 CPU:
8 Features: 000102030405060708090a0b0c0d0e0f0
9
10
11 # CHECK: String too long
12 # CHECK-NEXT: Features: 000102030405060708090a0b0c0d0e0f0
0 # RUN: not yaml2obj %s 2>&1 | FileCheck %s
1
2 --- !minidump
3 Streams:
4 - Type: SystemInfo
5 Processor Arch: PPC
6 Platform ID: Linux
7 CPU:
8 Features: 000102030405060708090a0b0c0d0e0g
9
10
11 # CHECK: Invalid hex digit in input
12 # CHECK-NEXT: Features: 000102030405060708090a0b0c0d0e0g
0 # RUN: not yaml2obj %s 2>&1 | FileCheck %s
1
2 --- !minidump
3 Streams:
4 - Type: SystemInfo
5 Processor Arch: PPC
6 Platform ID: Linux
7 CPU:
8 Features: 000102030405060708090a0b0c0d0e0
9
10
11 # CHECK: String too short
12 # CHECK-NEXT: Features: 000102030405060708090a0b0c0d0e0
0 # RUN: not yaml2obj %s 2>&1 | FileCheck %s
1
2 --- !minidump
3 Streams:
4 - Type: SystemInfo
5 Processor Arch: X86
6 Platform ID: Linux
7 CPU:
8 Vendor ID: LLVMLLVMLLVML
9 Version Info: 0x01020304
10 Feature Info: 0x05060708
11 AMD Extended Features: 0x09000102
12
13 # CHECK: String too long
14 # CHECK-NEXT: Vendor ID: LLVMLLVMLLVML
0 # RUN: not yaml2obj %s 2>&1 | FileCheck %s
1
2 --- !minidump
3 Streams:
4 - Type: SystemInfo
5 Processor Arch: X86
6 Platform ID: Linux
7 CPU:
8 Vendor ID: LLVMLLVMLLV
9 Version Info: 0x01020304
10 Feature Info: 0x05060708
11 AMD Extended Features: 0x09000102
12
13 # CHECK: String too short
14 # CHECK-NEXT: Vendor ID: LLVMLLVMLLV
1010 yaml2coff.cpp
1111 yaml2elf.cpp
1212 yaml2macho.cpp
13 yaml2minidump.cpp
1314 yaml2wasm.cpp
1415 )
0 //===- yaml2minidump.cpp - Convert a YAML file to a minidump file ---------===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7
8 #include "yaml2obj.h"
9 #include "llvm/ObjectYAML/MinidumpYAML.h"
10 #include "llvm/Support/raw_ostream.h"
11
12 using namespace llvm;
13
14 int yaml2minidump(MinidumpYAML::Object &Doc, raw_ostream &Out) {
15 writeAsBinary(Doc, Out);
16 return 0;
17 }
5555 return yaml2coff(*Doc.Coff, Out);
5656 if (Doc.MachO || Doc.FatMachO)
5757 return yaml2macho(Doc, Out);
58 if (Doc.Minidump)
59 return yaml2minidump(*Doc.Minidump, Out);
5860 if (Doc.Wasm)
5961 return yaml2wasm(*Doc.Wasm, Out);
6062 error("yaml2obj: Unknown document type!");
2121 struct Object;
2222 }
2323
24 namespace MinidumpYAML {
25 struct Object;
26 }
27
2428 namespace WasmYAML {
2529 struct Object;
2630 }
3438 int yaml2coff(llvm::COFFYAML::Object &Doc, llvm::raw_ostream &Out);
3539 int yaml2elf(llvm::ELFYAML::Object &Doc, llvm::raw_ostream &Out);
3640 int yaml2macho(llvm::yaml::YamlObjectFile &Doc, llvm::raw_ostream &Out);
41 int yaml2minidump(llvm::MinidumpYAML::Object &Doc, llvm::raw_ostream &Out);
3742 int yaml2wasm(llvm::WasmYAML::Object &Doc, llvm::raw_ostream &Out);
3843
3944 #endif
0 set(LLVM_LINK_COMPONENTS
1 Object
12 ObjectYAML
23 )
34
45 add_llvm_unittest(ObjectYAMLTests
6 MinidumpYAMLTest.cpp
57 YAMLTest.cpp
68 )
79
10 target_link_libraries(ObjectYAMLTests PRIVATE LLVMTestingSupport)
0 //===- MinidumpYAMLTest.cpp - Tests for Minidump<->YAML code --------------===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7
8 #include "llvm/ObjectYAML/MinidumpYAML.h"
9 #include "llvm/Object/Minidump.h"
10 #include "llvm/ObjectYAML/ObjectYAML.h"
11 #include "llvm/Testing/Support/Error.h"
12 #include "gtest/gtest.h"
13
14 using namespace llvm;
15 using namespace llvm::minidump;
16
17 static Expected>
18 toBinary(SmallVectorImpl &Storage, StringRef Yaml) {
19 Storage.clear();
20 raw_svector_ostream OS(Storage);
21 if (Error E = MinidumpYAML::writeAsBinary(Yaml, OS))
22 return std::move(E);
23
24 return object::MinidumpFile::create(MemoryBufferRef(OS.str(), "Binary"));
25 }
26
27 TEST(MinidumpYAML, Basic) {
28 SmallString<0> Storage;
29 auto ExpectedFile = toBinary(Storage, R"(
30 --- !minidump
31 Streams:
32 - Type: SystemInfo
33 Processor Arch: ARM64
34 Platform ID: Linux
35 CSD Version RVA: 0x01020304
36 CPU:
37 CPUID: 0x05060708
38 - Type: LinuxMaps
39 Text: |
40 400d9000-400db000 r-xp 00000000 b3:04 227 /system/bin/app_process
41 400db000-400dc000 r--p 00001000 b3:04 227 /system/bin/app_process
42
43 - Type: LinuxAuxv
44 Content: DEADBEEFBAADF00D)");
45 ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
46 object::MinidumpFile &File = **ExpectedFile;
47
48 ASSERT_EQ(3u, File.streams().size());
49
50 EXPECT_EQ(StreamType::SystemInfo, File.streams()[0].Type);
51 auto ExpectedSysInfo = File.getSystemInfo();
52 ASSERT_THAT_EXPECTED(ExpectedSysInfo, Succeeded());
53 const SystemInfo &SysInfo = *ExpectedSysInfo;
54 EXPECT_EQ(ProcessorArchitecture::ARM64, SysInfo.ProcessorArch);
55 EXPECT_EQ(OSPlatform::Linux, SysInfo.PlatformId);
56 EXPECT_EQ(0x01020304u, SysInfo.CSDVersionRVA);
57 EXPECT_EQ(0x05060708u, SysInfo.CPU.Arm.CPUID);
58
59 EXPECT_EQ(StreamType::LinuxMaps, File.streams()[1].Type);
60 EXPECT_EQ("400d9000-400db000 r-xp 00000000 b3:04 227 "
61 "/system/bin/app_process\n"
62 "400db000-400dc000 r--p 00001000 b3:04 227 "
63 "/system/bin/app_process\n",
64 toStringRef(*File.getRawStream(StreamType::LinuxMaps)));
65
66 EXPECT_EQ(StreamType::LinuxAuxv, File.streams()[2].Type);
67 EXPECT_EQ((ArrayRef{0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD, 0xF0, 0x0D}),
68 File.getRawStream(StreamType::LinuxAuxv));
69 }
70
71 TEST(MinidumpYAML, RawContent) {
72 SmallString<0> Storage;
73 auto ExpectedFile = toBinary(Storage, R"(
74 --- !minidump
75 Streams:
76 - Type: LinuxAuxv
77 Size: 9
78 Content: DEADBEEFBAADF00D)");
79 ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
80 object::MinidumpFile &File = **ExpectedFile;
81
82 EXPECT_EQ(
83 (ArrayRef{0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD, 0xF0, 0x0D, 0x00}),
84 File.getRawStream(StreamType::LinuxAuxv));
85 }
86
87 TEST(MinidumpYAML, X86SystemInfo) {
88 SmallString<0> Storage;
89 auto ExpectedFile = toBinary(Storage, R"(
90 --- !minidump
91 Streams:
92 - Type: SystemInfo
93 Processor Arch: X86
94 Platform ID: Linux
95 CPU:
96 Vendor ID: LLVMLLVMLLVM
97 Version Info: 0x01020304
98 Feature Info: 0x05060708
99 AMD Extended Features: 0x09000102)");
100 ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
101 object::MinidumpFile &File = **ExpectedFile;
102
103 ASSERT_EQ(1u, File.streams().size());
104
105 auto ExpectedSysInfo = File.getSystemInfo();
106 ASSERT_THAT_EXPECTED(ExpectedSysInfo, Succeeded());
107 const SystemInfo &SysInfo = *ExpectedSysInfo;
108 EXPECT_EQ(ProcessorArchitecture::X86, SysInfo.ProcessorArch);
109 EXPECT_EQ(OSPlatform::Linux, SysInfo.PlatformId);
110 EXPECT_EQ("LLVMLLVMLLVM", StringRef(SysInfo.CPU.X86.VendorID,
111 sizeof(SysInfo.CPU.X86.VendorID)));
112 EXPECT_EQ(0x01020304u, SysInfo.CPU.X86.VersionInfo);
113 EXPECT_EQ(0x05060708u, SysInfo.CPU.X86.FeatureInfo);
114 EXPECT_EQ(0x09000102u, SysInfo.CPU.X86.AMDExtendedFeatures);
115 }
116
117 TEST(MinidumpYAML, OtherSystemInfo) {
118 SmallString<0> Storage;
119 auto ExpectedFile = toBinary(Storage, R"(
120 --- !minidump
121 Streams:
122 - Type: SystemInfo
123 Processor Arch: PPC
124 Platform ID: Linux
125 CPU:
126 Features: 000102030405060708090a0b0c0d0e0f)");
127 ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
128 object::MinidumpFile &File = **ExpectedFile;
129
130 ASSERT_EQ(1u, File.streams().size());
131
132 auto ExpectedSysInfo = File.getSystemInfo();
133 ASSERT_THAT_EXPECTED(ExpectedSysInfo, Succeeded());
134 const SystemInfo &SysInfo = *ExpectedSysInfo;
135 EXPECT_EQ(ProcessorArchitecture::PPC, SysInfo.ProcessorArch);
136 EXPECT_EQ(OSPlatform::Linux, SysInfo.PlatformId);
137 EXPECT_EQ(
138 (ArrayRef{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}),
139 makeArrayRef(SysInfo.CPU.Other.ProcessorFeatures));
140 }