llvm.org GIT mirror llvm / a8e86b9
Add FileWriter to GSYM and encode/decode functions to AddressRange and AddressRanges The full GSYM patch started with: https://reviews.llvm.org/D53379 This patch add the ability to encode data using the new llvm::gsym::FileWriter class. FileWriter is a simplified binary data writer class that doesn't require targets, target definitions, architectures, or require any other optional compile time libraries to be enabled via the build process. This class needs the ability to seek to different spots in the binary data that it produces to fix up offsets and sizes in GSYM data. It currently uses std::ostream over llvm::raw_ostream because llvm::raw_ostream doesn't support seeking which is required when encoding and decoding GSYM data. AddressRange objects are encoded and decoded to be relative to a base address. This will be the FunctionInfo's start address if the AddressRange is directly contained in a FunctionInfo, or a base address of the containing parent AddressRange or AddressRanges. This allows address ranges to be efficiently encoded using ULEB128 encodings as we encode the offset and size of each range instead of full addresses. This also makes encoded addresses easy to relocate as we just need to relocate one base address. Differential Revision: https://reviews.llvm.org/D63828 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@369587 91177308-0d34-0410-b5e6-96231b3b80d8 Greg Clayton a month ago
11 changed file(s) with 395 addition(s) and 25 deletion(s). Raw diff Collapse all Expand all
0 //===- FileEntry.h ----------------------------------------------*- C++ -*-===//
11 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
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
65 //
76 //===----------------------------------------------------------------------===//
87
0 //===- FileWriter.h ---------------------------------------------*- 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_DEBUGINFO_GSYM_FILEWRITER_H
9 #define LLVM_DEBUGINFO_GSYM_FILEWRITER_H
10
11 #include "llvm/ADT/ArrayRef.h"
12 #include "llvm/Support/Endian.h"
13
14 #include
15 #include
16 #include
17
18 namespace llvm {
19 class raw_pwrite_stream;
20
21 namespace gsym {
22
23 /// A simplified binary data writer class that doesn't require targets, target
24 /// definitions, architectures, or require any other optional compile time
25 /// libraries to be enabled via the build process. This class needs the ability
26 /// to seek to different spots in the binary stream that is produces to fixup
27 /// offsets and sizes.
28 class FileWriter {
29 llvm::raw_pwrite_stream &OS;
30 llvm::support::endianness ByteOrder;
31 public:
32 FileWriter(llvm::raw_pwrite_stream &S, llvm::support::endianness B)
33 : OS(S), ByteOrder(B) {}
34 ~FileWriter();
35 /// Write a single uint8_t value into the stream at the current file
36 /// position.
37 ///
38 /// \param Value The value to write into the stream.
39 void writeU8(uint8_t Value);
40
41 /// Write a single uint16_t value into the stream at the current file
42 /// position. The value will be byte swapped if needed to match the byte
43 /// order specified during construction.
44 ///
45 /// \param Value The value to write into the stream.
46 void writeU16(uint16_t Value);
47
48 /// Write a single uint32_t value into the stream at the current file
49 /// position. The value will be byte swapped if needed to match the byte
50 /// order specified during construction.
51 ///
52 /// \param Value The value to write into the stream.
53 void writeU32(uint32_t Value);
54
55 /// Write a single uint64_t value into the stream at the current file
56 /// position. The value will be byte swapped if needed to match the byte
57 /// order specified during construction.
58 ///
59 /// \param Value The value to write into the stream.
60 void writeU64(uint64_t Value);
61
62 /// Write the value into the stream encoded using signed LEB128 at the
63 /// current file position.
64 ///
65 /// \param Value The value to write into the stream.
66 void writeSLEB(int64_t Value);
67
68 /// Write the value into the stream encoded using unsigned LEB128 at the
69 /// current file position.
70 ///
71 /// \param Value The value to write into the stream.
72 void writeULEB(uint64_t Value);
73
74 /// Write an array of uint8_t values into the stream at the current file
75 /// position.
76 ///
77 /// \param Data An array of values to write into the stream.
78 void writeData(llvm::ArrayRef Data);
79
80 /// Write a NULL terminated C string into the stream at the current file
81 /// position. The entire contents of Str will be written into the steam at
82 /// the current file position and then an extra NULL termation byte will be
83 /// written. It is up to the user to ensure that Str doesn't contain any NULL
84 /// characters unless the additional NULL characters are desired.
85 ///
86 /// \param Str The value to write into the stream.
87 void writeNullTerminated(llvm::StringRef Str);
88
89 /// Fixup a uint32_t value at the specified offset in the stream. This
90 /// function will save the current file position, seek to the specified
91 /// offset, overwrite the data using Value, and then restore the file
92 /// position to the previous file position.
93 ///
94 /// \param Value The value to write into the stream.
95 /// \param Offset The offset at which to write the Value within the stream.
96 void fixup32(uint32_t Value, uint64_t Offset);
97
98 /// Pad with zeroes at the current file position until the current file
99 /// position matches the specified alignment.
100 ///
101 /// \param Align An integer speciying the desired alignment. This does not
102 /// need to be a power of two.
103 void alignTo(size_t Align);
104
105 /// Return the current offset within the file.
106 ///
107 /// \return The unsigned offset from the start of the file of the current
108 /// file position.
109 uint64_t tell();
110
111 private:
112 FileWriter(const FileWriter &rhs) = delete;
113 void operator=(const FileWriter &rhs) = delete;
114 };
115
116 } // namespace gsym
117 } // namespace llvm
118
119 #endif // #ifndef LLVM_DEBUGINFO_GSYM_FILEWRITER_H
0 //===- FunctionInfo.h -------------------------------------------*- C++ -*-===//
11 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
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
65 //
76 //===----------------------------------------------------------------------===//
87
0 //===- InlineInfo.h ---------------------------------------------*- C++ -*-===//
11 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
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
65 //
76 //===----------------------------------------------------------------------===//
87
0 //===- LineEntry.h ----------------------------------------------*- C++ -*-===//
11 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
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
65 //
76 //===----------------------------------------------------------------------===//
87
0 //===- AddressRange.h -------------------------------------------*- C++ -*-===//
11 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
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
65 //
76 //===----------------------------------------------------------------------===//
87
2019 #define HEX64(v) llvm::format_hex(v, 18)
2120
2221 namespace llvm {
22 class DataExtractor;
2323 class raw_ostream;
2424
2525 namespace gsym {
26
27 class FileWriter;
2628
2729 /// A class that represents an address range. The range is specified using
2830 /// a start and an end address.
4648 bool operator<(const AddressRange &R) const {
4749 return std::make_pair(Start, End) < std::make_pair(R.Start, R.End);
4850 }
51 /// AddressRange objects are encoded and decoded to be relative to a base
52 /// address. This will be the FunctionInfo's start address if the AddressRange
53 /// is directly contained in a FunctionInfo, or a base address of the
54 /// containing parent AddressRange or AddressRanges. This allows address
55 /// ranges to be efficiently encoded using ULEB128 encodings as we encode the
56 /// offset and size of each range instead of full addresses. This also makes
57 /// encoded addresses easy to relocate as we just need to relocate one base
58 /// address.
59 /// @{
60 void decode(DataExtractor &Data, uint64_t BaseAddr, uint64_t &Offset);
61 void encode(FileWriter &O, uint64_t BaseAddr) const;
62 /// @}
4963 };
5064
5165 raw_ostream &operator<<(raw_ostream &OS, const AddressRange &R);
7690 }
7791 Collection::const_iterator begin() const { return Ranges.begin(); }
7892 Collection::const_iterator end() const { return Ranges.end(); }
93
94 /// Address ranges are decoded and encoded to be relative to a base address.
95 /// See the AddressRange comment for the encode and decode methods for full
96 /// details.
97 /// @{
98 void decode(DataExtractor &Data, uint64_t BaseAddr, uint64_t &Offset);
99 void encode(FileWriter &O, uint64_t BaseAddr) const;
100 /// @}
79101 };
80102
81103 raw_ostream &operator<<(raw_ostream &OS, const AddressRanges &AR);
0 //===- StringTable.h --------------------------------------------*- C++ -*-===//
11 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
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
65 //
76 //===----------------------------------------------------------------------===//
87
0 add_llvm_library(LLVMDebugInfoGSYM
1 FileWriter.cpp
12 FunctionInfo.cpp
23 InlineInfo.cpp
34 Range.cpp
0 //===- FileWriter.cpp -------------------------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/GSYM/FileWriter.h"
10 #include "llvm/Support/LEB128.h"
11 #include "llvm/Support/raw_ostream.h"
12 #include
13
14 using namespace llvm;
15 using namespace gsym;
16
17 FileWriter::~FileWriter() { OS.flush(); }
18
19 void FileWriter::writeSLEB(int64_t S) {
20 uint8_t Bytes[32];
21 auto Length = encodeSLEB128(S, Bytes);
22 assert(Length < sizeof(Bytes));
23 OS.write(reinterpret_cast(Bytes), Length);
24 }
25
26 void FileWriter::writeULEB(uint64_t U) {
27 uint8_t Bytes[32];
28 auto Length = encodeULEB128(U, Bytes);
29 assert(Length < sizeof(Bytes));
30 OS.write(reinterpret_cast(Bytes), Length);
31 }
32
33 void FileWriter::writeU8(uint8_t U) {
34 OS.write(reinterpret_cast(&U), sizeof(U));
35 }
36
37 void FileWriter::writeU16(uint16_t U) {
38 const uint16_t Swapped = support::endian::byte_swap(U, ByteOrder);
39 OS.write(reinterpret_cast(&Swapped), sizeof(Swapped));
40 }
41
42 void FileWriter::writeU32(uint32_t U) {
43 const uint32_t Swapped = support::endian::byte_swap(U, ByteOrder);
44 OS.write(reinterpret_cast(&Swapped), sizeof(Swapped));
45 }
46
47 void FileWriter::writeU64(uint64_t U) {
48 const uint64_t Swapped = support::endian::byte_swap(U, ByteOrder);
49 OS.write(reinterpret_cast(&Swapped), sizeof(Swapped));
50 }
51
52 void FileWriter::fixup32(uint32_t U, uint64_t Offset) {
53 const uint32_t Swapped = support::endian::byte_swap(U, ByteOrder);
54 OS.pwrite(reinterpret_cast(&Swapped), sizeof(Swapped),
55 Offset);
56 }
57
58 void FileWriter::writeData(llvm::ArrayRef Data) {
59 OS.write(reinterpret_cast(Data.data()), Data.size());
60 }
61
62 void FileWriter::writeNullTerminated(llvm::StringRef Str) {
63 OS << Str << '\0';
64 }
65
66 uint64_t FileWriter::tell() {
67 return OS.tell();
68 }
69
70 void FileWriter::alignTo(size_t Align) {
71 off_t Offset = OS.tell();
72 off_t AlignedOffset = (Offset + Align - 1) / Align * Align;
73 if (AlignedOffset == Offset)
74 return;
75 off_t PadCount = AlignedOffset - Offset;
76 OS.write_zeros(PadCount);
77 }
77 //===----------------------------------------------------------------------===//
88
99 #include "llvm/DebugInfo/GSYM/Range.h"
10 #include "llvm/DebugInfo/GSYM/FileWriter.h"
11 #include "llvm/Support/DataExtractor.h"
1012 #include
1113 #include
1214
5254 }
5355 return OS;
5456 }
57
58 void AddressRange::encode(FileWriter &O, uint64_t BaseAddr) const {
59 assert(Start >= BaseAddr);
60 O.writeULEB(Start - BaseAddr);
61 O.writeULEB(size());
62 }
63
64 void AddressRange::decode(DataExtractor &Data, uint64_t BaseAddr,
65 uint64_t &Offset) {
66 const uint64_t AddrOffset = Data.getULEB128(&Offset);
67 const uint64_t Size = Data.getULEB128(&Offset);
68 const uint64_t StartAddr = BaseAddr + AddrOffset;
69 Start = StartAddr;
70 End = StartAddr + Size;
71 }
72
73 void AddressRanges::encode(FileWriter &O, uint64_t BaseAddr) const {
74 O.writeULEB(Ranges.size());
75 if (Ranges.empty())
76 return;
77 for (auto Range : Ranges)
78 Range.encode(O, BaseAddr);
79 }
80
81 void AddressRanges::decode(DataExtractor &Data, uint64_t BaseAddr,
82 uint64_t &Offset) {
83 clear();
84 uint64_t NumRanges = Data.getULEB128(&Offset);
85 if (NumRanges == 0)
86 return;
87 Ranges.resize(NumRanges);
88 for (auto &Range : Ranges)
89 Range.decode(Data, BaseAddr, Offset);
90 }
77 //===----------------------------------------------------------------------===//
88
99 #include "llvm/ADT/DenseMap.h"
10 #include "llvm/ADT/SmallString.h"
1011 #include "llvm/DebugInfo/GSYM/FileEntry.h"
12 #include "llvm/DebugInfo/GSYM/FileWriter.h"
1113 #include "llvm/DebugInfo/GSYM/FunctionInfo.h"
1214 #include "llvm/DebugInfo/GSYM/InlineInfo.h"
1315 #include "llvm/DebugInfo/GSYM/Range.h"
1416 #include "llvm/DebugInfo/GSYM/StringTable.h"
15 #include "llvm/Testing/Support/Error.h"
17 #include "llvm/Support/DataExtractor.h"
18 #include "llvm/Support/Endian.h"
1619
1720 #include "gtest/gtest.h"
1821 #include
378381 // Test pointing to past end gets empty string.
379382 EXPECT_EQ(StrTab.getString(13), "");
380383 }
384
385 static void TestFileWriterHelper(llvm::support::endianness ByteOrder) {
386 SmallString<512> Str;
387 raw_svector_ostream OutStrm(Str);
388 FileWriter FW(OutStrm, ByteOrder);
389 const int64_t MinSLEB = INT64_MIN;
390 const int64_t MaxSLEB = INT64_MAX;
391 const uint64_t MinULEB = 0;
392 const uint64_t MaxULEB = UINT64_MAX;
393 const uint8_t U8 = 0x10;
394 const uint16_t U16 = 0x1122;
395 const uint32_t U32 = 0x12345678;
396 const uint64_t U64 = 0x33445566778899aa;
397 const char *Hello = "hello";
398 FW.writeU8(U8);
399 FW.writeU16(U16);
400 FW.writeU32(U32);
401 FW.writeU64(U64);
402 FW.alignTo(16);
403 const off_t FixupOffset = FW.tell();
404 FW.writeU32(0);
405 FW.writeSLEB(MinSLEB);
406 FW.writeSLEB(MaxSLEB);
407 FW.writeULEB(MinULEB);
408 FW.writeULEB(MaxULEB);
409 FW.writeNullTerminated(Hello);
410 // Test Seek, Tell using Fixup32.
411 FW.fixup32(U32, FixupOffset);
412
413 std::string Bytes(OutStrm.str());
414 uint8_t AddressSize = 4;
415 DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
416 uint64_t Offset = 0;
417 EXPECT_EQ(Data.getU8(&Offset), U8);
418 EXPECT_EQ(Data.getU16(&Offset), U16);
419 EXPECT_EQ(Data.getU32(&Offset), U32);
420 EXPECT_EQ(Data.getU64(&Offset), U64);
421 Offset = alignTo(Offset, 16);
422 EXPECT_EQ(Data.getU32(&Offset), U32);
423 EXPECT_EQ(Data.getSLEB128(&Offset), MinSLEB);
424 EXPECT_EQ(Data.getSLEB128(&Offset), MaxSLEB);
425 EXPECT_EQ(Data.getULEB128(&Offset), MinULEB);
426 EXPECT_EQ(Data.getULEB128(&Offset), MaxULEB);
427 EXPECT_EQ(Data.getCStrRef(&Offset), StringRef(Hello));
428 }
429
430 TEST(GSYMTest, TestFileWriter) {
431 TestFileWriterHelper(llvm::support::little);
432 TestFileWriterHelper(llvm::support::big);
433 }
434
435 TEST(GSYMTest, TestAddressRangeEncodeDecode) {
436 // Test encoding and decoding AddressRange objects. AddressRange objects
437 // are always stored as offsets from the a base address. The base address
438 // is the FunctionInfo's base address for function level ranges, and is
439 // the base address of the parent range for subranges.
440 SmallString<512> Str;
441 raw_svector_ostream OutStrm(Str);
442 const auto ByteOrder = llvm::support::endian::system_endianness();
443 FileWriter FW(OutStrm, ByteOrder);
444 const uint64_t BaseAddr = 0x1000;
445 const AddressRange Range1(0x1000, 0x1010);
446 const AddressRange Range2(0x1020, 0x1030);
447 Range1.encode(FW, BaseAddr);
448 Range2.encode(FW, BaseAddr);
449 std::string Bytes(OutStrm.str());
450 uint8_t AddressSize = 4;
451 DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
452
453 AddressRange DecodedRange1, DecodedRange2;
454 uint64_t Offset = 0;
455 DecodedRange1.decode(Data, BaseAddr, Offset);
456 DecodedRange2.decode(Data, BaseAddr, Offset);
457 EXPECT_EQ(Range1, DecodedRange1);
458 EXPECT_EQ(Range2, DecodedRange2);
459 }
460
461 static void TestAddressRangeEncodeDecodeHelper(const AddressRanges &Ranges,
462 const uint64_t BaseAddr) {
463 SmallString<512> Str;
464 raw_svector_ostream OutStrm(Str);
465 const auto ByteOrder = llvm::support::endian::system_endianness();
466 FileWriter FW(OutStrm, ByteOrder);
467 Ranges.encode(FW, BaseAddr);
468
469 std::string Bytes(OutStrm.str());
470 uint8_t AddressSize = 4;
471 DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
472
473 AddressRanges DecodedRanges;
474 uint64_t Offset = 0;
475 DecodedRanges.decode(Data, BaseAddr, Offset);
476 EXPECT_EQ(Ranges, DecodedRanges);
477 }
478
479 TEST(GSYMTest, TestAddressRangesEncodeDecode) {
480 // Test encoding and decoding AddressRanges. AddressRanges objects contain
481 // ranges that are stored as offsets from the a base address. The base address
482 // is the FunctionInfo's base address for function level ranges, and is the
483 // base address of the parent range for subranges.
484 const uint64_t BaseAddr = 0x1000;
485
486 // Test encoding and decoding with no ranges.
487 AddressRanges Ranges;
488 TestAddressRangeEncodeDecodeHelper(Ranges, BaseAddr);
489
490 // Test encoding and decoding with 1 range.
491 Ranges.insert(AddressRange(0x1000, 0x1010));
492 TestAddressRangeEncodeDecodeHelper(Ranges, BaseAddr);
493
494 // Test encoding and decoding with multiple ranges.
495 Ranges.insert(AddressRange(0x1020, 0x1030));
496 Ranges.insert(AddressRange(0x1050, 0x1070));
497 TestAddressRangeEncodeDecodeHelper(Ranges, BaseAddr);
498 }