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
|
// Copyright 2011-2022, Molecular Matters GmbH <[email protected]>
// See LICENSE.txt for licensing details (2-clause BSD License: https://opensource.org/licenses/BSD-2-Clause)
#include "PDB_PCH.h"
#include "PDB_IPIStream.h"
#include "PDB_RawFile.h"
#include "PDB_Util.h"
#include "PDB_DirectMSFStream.h"
#include "PDB_InfoStream.h"
#include "Foundation/PDB_Memory.h"
namespace
{
// the IPI stream always resides at index 4
static constexpr const uint32_t IPIStreamIndex = 4u;
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
PDB::IPIStream::IPIStream(void) PDB_NO_EXCEPT
: m_header()
, m_stream()
, m_records(nullptr)
, m_recordCount(0u)
{
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
PDB::IPIStream::IPIStream(IPIStream&& other) PDB_NO_EXCEPT
: m_header(PDB_MOVE(other.m_header))
, m_stream(PDB_MOVE(other.m_stream))
, m_records(PDB_MOVE(other.m_records))
, m_recordCount(PDB_MOVE(other.m_recordCount))
{
other.m_records = nullptr;
other.m_recordCount = 0u;
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
PDB::IPIStream& PDB::IPIStream::operator=(IPIStream&& other) PDB_NO_EXCEPT
{
if (this != &other)
{
PDB_DELETE_ARRAY(m_records);
m_header = PDB_MOVE(other.m_header);
m_stream = PDB_MOVE(other.m_stream);
m_records = PDB_MOVE(other.m_records);
m_recordCount = PDB_MOVE(other.m_recordCount);
other.m_records = nullptr;
other.m_recordCount = 0u;
}
return *this;
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
PDB::IPIStream::IPIStream(const RawFile& file, const IPI::StreamHeader& header) PDB_NO_EXCEPT
: m_header(header)
, m_stream(file.CreateMSFStream<CoalescedMSFStream>(IPIStreamIndex))
, m_records(nullptr)
, m_recordCount(GetLastTypeIndex() - GetFirstTypeIndex())
{
// types in the IPI stream are accessed by their index from other streams.
// however, the index is not stored with types in the IPI stream directly, but has to be built while walking the stream.
// similarly, because types are variable-length records, there are no direct offsets to access individual types.
// we therefore walk the IPI stream once, and store pointers to the records for trivial O(N) array lookup by index later.
m_records = PDB_NEW_ARRAY(const CodeView::IPI::Record*, m_recordCount);
// ignore the stream's header
size_t offset = sizeof(IPI::StreamHeader);
// parse the CodeView records
uint32_t typeIndex = 0u;
while (offset < m_stream.GetSize())
{
// https://llvm.org/docs/PDB/CodeViewTypes.html
const CodeView::IPI::Record* record = m_stream.GetDataAtOffset<const CodeView::IPI::Record>(offset);
const uint32_t recordSize = GetCodeViewRecordSize(record);
m_records[typeIndex] = record;
// position the stream offset at the next record
offset += sizeof(CodeView::IPI::RecordHeader) + recordSize;
++typeIndex;
}
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
PDB::IPIStream::~IPIStream(void) PDB_NO_EXCEPT
{
PDB_DELETE_ARRAY(m_records);
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
PDB_NO_DISCARD PDB::ErrorCode PDB::HasValidIPIStream(const RawFile& file) PDB_NO_EXCEPT
{
const PDB::InfoStream infoStream(file);
if (!infoStream.HasIPIStream())
{
return ErrorCode::InvalidStream;
}
DirectMSFStream stream = file.CreateMSFStream<DirectMSFStream>(IPIStreamIndex);
if (stream.GetSize() < sizeof(IPI::StreamHeader))
{
return ErrorCode::InvalidStream;
}
const IPI::StreamHeader header = stream.ReadAtOffset<IPI::StreamHeader>(0u);
if (header.version != IPI::StreamHeader::Version::V80)
{
return ErrorCode::UnknownVersion;
}
return ErrorCode::Success;
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
PDB_NO_DISCARD PDB::IPIStream PDB::CreateIPIStream(const RawFile& file) PDB_NO_EXCEPT
{
DirectMSFStream stream = file.CreateMSFStream<DirectMSFStream>(IPIStreamIndex);
const IPI::StreamHeader header = stream.ReadAtOffset<IPI::StreamHeader>(0u);
return IPIStream { file, header };
}
|