1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
#pragma once
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
//===- Range.h --------------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_GSYM_RANGE_H
#define LLVM_DEBUGINFO_GSYM_RANGE_H
#include "llvm/ADT/Optional.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include <stdint.h>
#include <vector>
#define HEX8(v) llvm::format_hex(v, 4)
#define HEX16(v) llvm::format_hex(v, 6)
#define HEX32(v) llvm::format_hex(v, 10)
#define HEX64(v) llvm::format_hex(v, 18)
namespace llvm {
class DataExtractor;
class raw_ostream;
namespace gsym {
class FileWriter;
/// A class that represents an address range. The range is specified using
/// a start and an end address.
struct AddressRange {
uint64_t Start;
uint64_t End;
AddressRange() : Start(0), End(0) {}
AddressRange(uint64_t S, uint64_t E) : Start(S), End(E) {}
uint64_t size() const { return End - Start; }
bool contains(uint64_t Addr) const { return Start <= Addr && Addr < End; }
bool intersects(const AddressRange &R) const {
return Start < R.End && R.Start < End;
}
bool operator==(const AddressRange &R) const {
return Start == R.Start && End == R.End;
}
bool operator!=(const AddressRange &R) const {
return !(*this == R);
}
bool operator<(const AddressRange &R) const {
return std::make_pair(Start, End) < std::make_pair(R.Start, R.End);
}
/// 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.
/// @{
void decode(DataExtractor &Data, uint64_t BaseAddr, uint64_t &Offset);
void encode(FileWriter &O, uint64_t BaseAddr) const;
/// @}
/// Skip an address range object in the specified data a the specified
/// offset.
///
/// \param Data The binary stream to read the data from.
///
/// \param Offset The byte offset within \a Data.
static void skip(DataExtractor &Data, uint64_t &Offset);
};
raw_ostream &operator<<(raw_ostream &OS, const AddressRange &R);
/// The AddressRanges class helps normalize address range collections.
/// This class keeps a sorted vector of AddressRange objects and can perform
/// insertions and searches efficiently. The address ranges are always sorted
/// and never contain any invalid or empty address ranges. This allows us to
/// emit address ranges into the GSYM file efficiently. Intersecting address
/// ranges are combined during insertion so that we can emit the most compact
/// representation for address ranges when writing to disk.
class AddressRanges {
protected:
using Collection = std::vector<AddressRange>;
Collection Ranges;
public:
void clear() { Ranges.clear(); }
bool empty() const { return Ranges.empty(); }
bool contains(uint64_t Addr) const;
bool contains(AddressRange Range) const;
Optional<AddressRange> getRangeThatContains(uint64_t Addr) const;
void insert(AddressRange Range);
size_t size() const { return Ranges.size(); }
bool operator==(const AddressRanges &RHS) const {
return Ranges == RHS.Ranges;
}
const AddressRange &operator[](size_t i) const {
assert(i < Ranges.size());
return Ranges[i];
}
Collection::const_iterator begin() const { return Ranges.begin(); }
Collection::const_iterator end() const { return Ranges.end(); }
/// Address ranges are decoded and encoded to be relative to a base address.
/// See the AddressRange comment for the encode and decode methods for full
/// details.
/// @{
void decode(DataExtractor &Data, uint64_t BaseAddr, uint64_t &Offset);
void encode(FileWriter &O, uint64_t BaseAddr) const;
/// @}
/// Skip an address range object in the specified data a the specified
/// offset.
///
/// \param Data The binary stream to read the data from.
///
/// \param Offset The byte offset within \a Data.
///
/// \returns The number of address ranges that were skipped.
static uint64_t skip(DataExtractor &Data, uint64_t &Offset);
};
raw_ostream &operator<<(raw_ostream &OS, const AddressRanges &AR);
} // namespace gsym
} // namespace llvm
#endif // #ifndef LLVM_DEBUGINFO_GSYM_RANGE_H
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
|