1 //===-- PdbSymUid.h ---------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 // A unique identification scheme for Pdb records.
10 // The scheme is to partition a 64-bit integer into an 8-bit tag field, which
11 // will contain some value from the PDB_SymType enumeration.  The format of the
12 // other 48-bits depend on the tag, but must be sufficient to locate the
13 // corresponding entry in the underlying PDB file quickly.  For example, for
14 // a compile unit, we use 2 bytes to represent the index, which allows fast
15 // access to the compile unit's information.
16 //===----------------------------------------------------------------------===//
17 
18 #ifndef LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBSYMUID_H
19 #define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBSYMUID_H
20 
21 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
22 #include "llvm/DebugInfo/PDB/PDBTypes.h"
23 #include "llvm/Support/Compiler.h"
24 
25 #include "lldb/Utility/LLDBAssert.h"
26 #include "lldb/lldb-types.h"
27 
28 namespace lldb_private {
29 namespace npdb {
30 
31 // **important** - All concrete id types must have the 1-byte tag field at
32 // the beginning so that the types are all layout-compatible with each
33 // other, which is necessary in order to be able to safely access the tag
34 // member through any union member.
35 struct PdbCompilandId {
36   uint64_t tag : 8;   // PDB_SymType::Compiland
37   uint64_t modi : 16; // 0-based index of module in PDB
38   uint64_t unused : 32;
39 };
40 struct PdbCuSymId {
41   uint64_t tag : 8; // PDB_SymType::Data, Function, Block, etc.
42   uint64_t
43       offset : 30;     // Offset of symbol's record in module stream.  This is
44                        // offset by 4 from the CVSymbolArray's notion of offset
45                        // due to the debug magic at the beginning of the stream.
46   uint64_t global : 1; // True if this is from the globals stream.
47   uint64_t unused : 1;
48   uint64_t modi : 16; // For non-global, this is the 0-based index of module.
49 };
50 
51 struct PdbTypeSymId {
52   uint64_t tag : 8;    // PDB_SymType::FunctionSig, Enum, PointerType, etc.
53   uint64_t is_ipi : 8; // 1 if this value is from the IPI stream, 0 for TPI.
54   uint64_t unused : 16;
55   uint64_t index : 32; // codeview::TypeIndex
56 };
57 
58 static_assert(sizeof(PdbCompilandId) == 8, "invalid uid size");
59 static_assert(sizeof(PdbCuSymId) == 8, "invalid uid size");
60 static_assert(std::is_standard_layout<PdbCompilandId>::value,
61               "type is not standard layout!");
62 static_assert(std::is_standard_layout<PdbCuSymId>::value,
63               "type is not standard layout!");
64 
65 class PdbSymUid {
66   union {
67     PdbCompilandId comp_id;
68     PdbCuSymId cu_sym;
69     PdbTypeSymId type_sym;
70   } m_uid;
71 
72   PdbSymUid() { ::memset(&m_uid, 0, sizeof(m_uid)); }
73 
74 public:
75   static bool isTypeSym(llvm::pdb::PDB_SymType tag) {
76     switch (tag) {
77     case llvm::pdb::PDB_SymType::ArrayType:
78     case llvm::pdb::PDB_SymType::BaseClass:
79     case llvm::pdb::PDB_SymType::BaseInterface:
80     case llvm::pdb::PDB_SymType::BuiltinType:
81     case llvm::pdb::PDB_SymType::CustomType:
82     case llvm::pdb::PDB_SymType::Enum:
83     case llvm::pdb::PDB_SymType::FunctionArg:
84     case llvm::pdb::PDB_SymType::FunctionSig:
85     case llvm::pdb::PDB_SymType::Typedef:
86     case llvm::pdb::PDB_SymType::VectorType:
87     case llvm::pdb::PDB_SymType::VTableShape:
88     case llvm::pdb::PDB_SymType::PointerType:
89     case llvm::pdb::PDB_SymType::UDT:
90       return true;
91     default:
92       return false;
93     }
94   }
95 
96   static bool isCuSym(llvm::pdb::PDB_SymType tag) {
97     switch (tag) {
98     case llvm::pdb::PDB_SymType::Block:
99     case llvm::pdb::PDB_SymType::Callee:
100     case llvm::pdb::PDB_SymType::Caller:
101     case llvm::pdb::PDB_SymType::CallSite:
102     case llvm::pdb::PDB_SymType::CoffGroup:
103     case llvm::pdb::PDB_SymType::CompilandDetails:
104     case llvm::pdb::PDB_SymType::CompilandEnv:
105     case llvm::pdb::PDB_SymType::Custom:
106     case llvm::pdb::PDB_SymType::Data:
107     case llvm::pdb::PDB_SymType::Function:
108     case llvm::pdb::PDB_SymType::Inlinee:
109     case llvm::pdb::PDB_SymType::InlineSite:
110     case llvm::pdb::PDB_SymType::Label:
111     case llvm::pdb::PDB_SymType::Thunk:
112       return true;
113     default:
114       return false;
115     }
116   }
117 
118   static PdbSymUid makeCuSymId(llvm::codeview::ProcRefSym sym) {
119     return makeCuSymId(llvm::pdb::PDB_SymType::Function, sym.Module - 1,
120                        sym.SymOffset);
121   }
122 
123   static PdbSymUid makeCuSymId(llvm::pdb::PDB_SymType type, uint16_t modi,
124                                uint32_t offset) {
125     lldbassert(isCuSym(type));
126 
127     PdbSymUid uid;
128     uid.m_uid.cu_sym.modi = modi;
129     uid.m_uid.cu_sym.offset = offset;
130     uid.m_uid.cu_sym.global = false;
131     uid.m_uid.cu_sym.tag = static_cast<uint8_t>(type);
132     return uid;
133   }
134 
135   static PdbSymUid makeGlobalVariableUid(uint32_t offset) {
136     PdbSymUid uid = {};
137     uid.m_uid.cu_sym.modi = 0;
138     uid.m_uid.cu_sym.offset = offset;
139     uid.m_uid.cu_sym.global = 1;
140     uid.m_uid.cu_sym.unused = 0;
141     uid.m_uid.cu_sym.tag = static_cast<uint8_t>(llvm::pdb::PDB_SymType::Data);
142     return uid;
143   }
144 
145   static PdbSymUid makeCompilandId(llvm::codeview::ProcRefSym sym) {
146     // S_PROCREF symbols are 1-based
147     lldbassert(sym.Module > 0);
148     return makeCompilandId(sym.Module - 1);
149   }
150 
151   static PdbSymUid makeCompilandId(uint16_t modi) {
152     PdbSymUid uid;
153     uid.m_uid.comp_id.modi = modi;
154     uid.m_uid.cu_sym.tag =
155         static_cast<uint8_t>(llvm::pdb::PDB_SymType::Compiland);
156     return uid;
157   }
158 
159   static PdbSymUid makeTypeSymId(llvm::pdb::PDB_SymType type,
160                                  llvm::codeview::TypeIndex index, bool is_ipi) {
161     lldbassert(isTypeSym(type));
162 
163     PdbSymUid uid;
164     uid.m_uid.type_sym.tag = static_cast<uint8_t>(type);
165     uid.m_uid.type_sym.index = index.getIndex();
166     uid.m_uid.type_sym.is_ipi = static_cast<uint8_t>(is_ipi);
167     return uid;
168   }
169 
170   static PdbSymUid fromOpaqueId(uint64_t value) {
171     PdbSymUid result;
172     ::memcpy(&result.m_uid, &value, sizeof(value));
173     return result;
174   }
175 
176   uint64_t toOpaqueId() const {
177     uint64_t result;
178     ::memcpy(&result, &m_uid, sizeof(m_uid));
179     return result;
180   }
181 
182   bool isPubSym() const {
183     return tag() == llvm::pdb::PDB_SymType::PublicSymbol;
184   }
185   bool isCompiland() const {
186     return tag() == llvm::pdb::PDB_SymType::Compiland;
187   }
188   bool isGlobalVariable() const {
189     if (tag() != llvm::pdb::PDB_SymType::Data)
190       return false;
191     return static_cast<bool>(asCuSym().global);
192   }
193 
194   llvm::pdb::PDB_SymType tag() const {
195     return static_cast<llvm::pdb::PDB_SymType>(m_uid.comp_id.tag);
196   }
197 
198   const PdbCompilandId &asCompiland() const {
199     lldbassert(tag() == llvm::pdb::PDB_SymType::Compiland);
200     return m_uid.comp_id;
201   }
202 
203   const PdbCuSymId &asCuSym() const {
204     lldbassert(isCuSym(tag()));
205     return m_uid.cu_sym;
206   }
207 
208   const PdbTypeSymId &asTypeSym() const {
209     lldbassert(isTypeSym(tag()));
210     return m_uid.type_sym;
211   }
212 };
213 
214 struct SymbolAndUid {
215   llvm::codeview::CVSymbol sym;
216   PdbSymUid uid;
217 };
218 } // namespace npdb
219 } // namespace lldb_private
220 
221 #endif
222