1bdd1243dSDimitry Andric //===-- LVLocation.cpp ----------------------------------------------------===//
2bdd1243dSDimitry Andric //
3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bdd1243dSDimitry Andric //
7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
8bdd1243dSDimitry Andric //
9bdd1243dSDimitry Andric // This implements the LVOperation and LVLocation classes.
10bdd1243dSDimitry Andric //
11bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
12bdd1243dSDimitry Andric 
13bdd1243dSDimitry Andric #include "llvm/DebugInfo/LogicalView/Core/LVLocation.h"
14bdd1243dSDimitry Andric #include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
15bdd1243dSDimitry Andric #include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
16bdd1243dSDimitry Andric #include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
17bdd1243dSDimitry Andric 
18bdd1243dSDimitry Andric using namespace llvm;
19bdd1243dSDimitry Andric using namespace llvm::logicalview;
20bdd1243dSDimitry Andric 
21bdd1243dSDimitry Andric #define DEBUG_TYPE "Location"
22bdd1243dSDimitry Andric 
print(raw_ostream & OS,bool Full) const23bdd1243dSDimitry Andric void LVOperation::print(raw_ostream &OS, bool Full) const {}
24bdd1243dSDimitry Andric 
25bdd1243dSDimitry Andric // Identify the most common type of operations and print them using a high
26bdd1243dSDimitry Andric // level format, trying to isolate the DWARF complexity.
getOperandsDWARFInfo()27bdd1243dSDimitry Andric std::string LVOperation::getOperandsDWARFInfo() {
28bdd1243dSDimitry Andric   std::string String;
29bdd1243dSDimitry Andric   raw_string_ostream Stream(String);
30bdd1243dSDimitry Andric 
31bdd1243dSDimitry Andric   auto PrintRegisterInfo = [&](LVSmall Code) {
32bdd1243dSDimitry Andric     //-----------------------------------------------------------------------
33bdd1243dSDimitry Andric     // 2.5.1.1 Literal encodings.
34bdd1243dSDimitry Andric     //-----------------------------------------------------------------------
35bdd1243dSDimitry Andric     if (dwarf::DW_OP_lit0 <= Code && Code <= dwarf::DW_OP_lit31) {
36bdd1243dSDimitry Andric       Stream << format("lit%d", Code - dwarf::DW_OP_lit0);
37bdd1243dSDimitry Andric       return;
38bdd1243dSDimitry Andric     }
39bdd1243dSDimitry Andric 
40bdd1243dSDimitry Andric     //-----------------------------------------------------------------------
41bdd1243dSDimitry Andric     // 2.5.1.2 Register values.
42bdd1243dSDimitry Andric     //-----------------------------------------------------------------------
43bdd1243dSDimitry Andric     if (dwarf::DW_OP_breg0 <= Code && Code <= dwarf::DW_OP_breg31) {
44bdd1243dSDimitry Andric       std::string RegisterName(getReader().getRegisterName(Code, Operands));
45bdd1243dSDimitry Andric       Stream << format("breg%d+%d%s", Code - dwarf::DW_OP_breg0, Operands[0],
46bdd1243dSDimitry Andric                        RegisterName.c_str());
47bdd1243dSDimitry Andric       return;
48bdd1243dSDimitry Andric     }
49bdd1243dSDimitry Andric 
50bdd1243dSDimitry Andric     //-----------------------------------------------------------------------
51bdd1243dSDimitry Andric     // 2.6.1.1.3 Register location descriptions.
52bdd1243dSDimitry Andric     //-----------------------------------------------------------------------
53bdd1243dSDimitry Andric     if (dwarf::DW_OP_reg0 <= Code && Code <= dwarf::DW_OP_reg31) {
54bdd1243dSDimitry Andric       std::string RegisterName(getReader().getRegisterName(Code, Operands));
55bdd1243dSDimitry Andric       Stream << format("reg%d%s", Code - dwarf::DW_OP_reg0,
56bdd1243dSDimitry Andric                        RegisterName.c_str());
57bdd1243dSDimitry Andric       return;
58bdd1243dSDimitry Andric     }
59bdd1243dSDimitry Andric 
60bdd1243dSDimitry Andric     Stream << format("#0x%02x ", Code) << hexString(Operands[0]) << " "
61bdd1243dSDimitry Andric            << hexString(Operands[1]) << "#";
62bdd1243dSDimitry Andric   };
63bdd1243dSDimitry Andric 
64bdd1243dSDimitry Andric   switch (Opcode) {
65bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
66bdd1243dSDimitry Andric   // 2.5.1.1 Literal encodings.
67bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
68bdd1243dSDimitry Andric   case dwarf::DW_OP_addr:
69bdd1243dSDimitry Andric     Stream << "addr " << hexString(Operands[0]);
70bdd1243dSDimitry Andric     break;
71bdd1243dSDimitry Andric   case dwarf::DW_OP_constu:
72bdd1243dSDimitry Andric   case dwarf::DW_OP_const1u:
73bdd1243dSDimitry Andric   case dwarf::DW_OP_const2u:
74bdd1243dSDimitry Andric   case dwarf::DW_OP_const4u:
75bdd1243dSDimitry Andric   case dwarf::DW_OP_const8u:
76bdd1243dSDimitry Andric     Stream << "const_u " << unsigned(Operands[0]);
77bdd1243dSDimitry Andric     break;
78bdd1243dSDimitry Andric   case dwarf::DW_OP_consts:
79bdd1243dSDimitry Andric   case dwarf::DW_OP_const1s:
80bdd1243dSDimitry Andric   case dwarf::DW_OP_const2s:
81bdd1243dSDimitry Andric   case dwarf::DW_OP_const4s:
82bdd1243dSDimitry Andric   case dwarf::DW_OP_const8s:
83bdd1243dSDimitry Andric     Stream << "const_s " << int(Operands[0]);
84bdd1243dSDimitry Andric     break;
85bdd1243dSDimitry Andric   case dwarf::DW_OP_addrx:
86bdd1243dSDimitry Andric     Stream << "addrx " << unsigned(Operands[0]);
87bdd1243dSDimitry Andric     break;
88bdd1243dSDimitry Andric   case dwarf::DW_OP_constx:
89bdd1243dSDimitry Andric     Stream << "constx " << unsigned(Operands[0]);
90bdd1243dSDimitry Andric     break;
91bdd1243dSDimitry Andric   case dwarf::DW_OP_const_type:
92bdd1243dSDimitry Andric     Stream << "TODO: DW_OP_const_type";
93bdd1243dSDimitry Andric     break;
94bdd1243dSDimitry Andric 
95bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
96bdd1243dSDimitry Andric   // 2.5.1.2 Register values.
97bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
98bdd1243dSDimitry Andric   case dwarf::DW_OP_fbreg:
99bdd1243dSDimitry Andric     Stream << "fbreg " << int(Operands[0]);
100bdd1243dSDimitry Andric     break;
101bdd1243dSDimitry Andric   case dwarf::DW_OP_bregx: {
102bdd1243dSDimitry Andric     std::string RegisterName(getReader().getRegisterName(Opcode, Operands));
103bdd1243dSDimitry Andric     Stream << format("bregx %d%s+%d", Operands[0], RegisterName.c_str(),
104bdd1243dSDimitry Andric                      unsigned(Operands[1]));
105bdd1243dSDimitry Andric     break;
106bdd1243dSDimitry Andric   }
107bdd1243dSDimitry Andric   case dwarf::DW_OP_regval_type: {
108bdd1243dSDimitry Andric     std::string RegisterName(getReader().getRegisterName(Opcode, Operands));
109bdd1243dSDimitry Andric     Stream << format("regval_type %d%s+%d", Operands[0], RegisterName.c_str(),
110bdd1243dSDimitry Andric                      unsigned(Operands[1]));
111bdd1243dSDimitry Andric     break;
112bdd1243dSDimitry Andric   }
113bdd1243dSDimitry Andric 
114bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
115bdd1243dSDimitry Andric   // 2.5.1.3 Stack operations.
116bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
117bdd1243dSDimitry Andric   case dwarf::DW_OP_dup:
118bdd1243dSDimitry Andric     Stream << "dup";
119bdd1243dSDimitry Andric     break;
120bdd1243dSDimitry Andric   case dwarf::DW_OP_drop:
121bdd1243dSDimitry Andric     Stream << "drop";
122bdd1243dSDimitry Andric     break;
123bdd1243dSDimitry Andric   case dwarf::DW_OP_pick:
124bdd1243dSDimitry Andric     Stream << "pick " << unsigned(Operands[0]);
125bdd1243dSDimitry Andric     break;
126bdd1243dSDimitry Andric   case dwarf::DW_OP_over:
127bdd1243dSDimitry Andric     Stream << "over";
128bdd1243dSDimitry Andric     break;
129bdd1243dSDimitry Andric   case dwarf::DW_OP_swap:
130bdd1243dSDimitry Andric     Stream << "swap";
131bdd1243dSDimitry Andric     break;
132bdd1243dSDimitry Andric   case dwarf::DW_OP_rot:
133bdd1243dSDimitry Andric     Stream << "rot";
134bdd1243dSDimitry Andric     break;
135bdd1243dSDimitry Andric   case dwarf::DW_OP_deref:
136bdd1243dSDimitry Andric     Stream << "deref";
137bdd1243dSDimitry Andric     break;
138bdd1243dSDimitry Andric   case dwarf::DW_OP_deref_size:
139bdd1243dSDimitry Andric     Stream << "deref_size " << unsigned(Operands[0]);
140bdd1243dSDimitry Andric     break;
141bdd1243dSDimitry Andric   case dwarf::DW_OP_deref_type:
142bdd1243dSDimitry Andric     Stream << "deref_type " << unsigned(Operands[0]) << " DIE offset "
143bdd1243dSDimitry Andric            << hexString(Operands[1]);
144bdd1243dSDimitry Andric     break;
145bdd1243dSDimitry Andric   case dwarf::DW_OP_xderef:
146bdd1243dSDimitry Andric     Stream << "xderef";
147bdd1243dSDimitry Andric     break;
148bdd1243dSDimitry Andric   case dwarf::DW_OP_xderef_size:
149bdd1243dSDimitry Andric     Stream << "xderef_size " << unsigned(Operands[0]);
150bdd1243dSDimitry Andric     break;
151bdd1243dSDimitry Andric   case dwarf::DW_OP_xderef_type:
152bdd1243dSDimitry Andric     Stream << "xderef_type " << unsigned(Operands[0]) << " DIE offset "
153bdd1243dSDimitry Andric            << hexString(Operands[1]);
154bdd1243dSDimitry Andric     break;
155bdd1243dSDimitry Andric   case dwarf::DW_OP_push_object_address:
156bdd1243dSDimitry Andric     Stream << "push_object_address";
157bdd1243dSDimitry Andric     break;
158bdd1243dSDimitry Andric   case dwarf::DW_OP_form_tls_address:
159bdd1243dSDimitry Andric     Stream << "form_tls_address " << hexString(Operands[0]);
160bdd1243dSDimitry Andric     break;
161bdd1243dSDimitry Andric   case dwarf::DW_OP_call_frame_cfa:
162bdd1243dSDimitry Andric     Stream << "call_frame_cfa";
163bdd1243dSDimitry Andric     break;
164bdd1243dSDimitry Andric 
165bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
166bdd1243dSDimitry Andric   // 2.5.1.4 Arithmetic and Logical Operations.
167bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
168bdd1243dSDimitry Andric   case dwarf::DW_OP_abs:
169bdd1243dSDimitry Andric     Stream << "abs";
170bdd1243dSDimitry Andric     break;
171bdd1243dSDimitry Andric   case dwarf::DW_OP_and:
172bdd1243dSDimitry Andric     Stream << "and";
173bdd1243dSDimitry Andric     break;
174bdd1243dSDimitry Andric   case dwarf::DW_OP_div:
175bdd1243dSDimitry Andric     Stream << "div";
176bdd1243dSDimitry Andric     break;
177bdd1243dSDimitry Andric   case dwarf::DW_OP_minus:
178bdd1243dSDimitry Andric     Stream << "minus";
179bdd1243dSDimitry Andric     break;
180bdd1243dSDimitry Andric   case dwarf::DW_OP_mod:
181bdd1243dSDimitry Andric     Stream << "mod";
182bdd1243dSDimitry Andric     break;
183bdd1243dSDimitry Andric   case dwarf::DW_OP_mul:
184bdd1243dSDimitry Andric     Stream << "mul";
185bdd1243dSDimitry Andric     break;
186bdd1243dSDimitry Andric   case dwarf::DW_OP_neg:
187bdd1243dSDimitry Andric     Stream << "neg";
188bdd1243dSDimitry Andric     break;
189bdd1243dSDimitry Andric   case dwarf::DW_OP_not:
190bdd1243dSDimitry Andric     Stream << "not";
191bdd1243dSDimitry Andric     break;
192bdd1243dSDimitry Andric   case dwarf::DW_OP_or:
193bdd1243dSDimitry Andric     Stream << "or";
194bdd1243dSDimitry Andric     break;
195bdd1243dSDimitry Andric   case dwarf::DW_OP_plus:
196bdd1243dSDimitry Andric     Stream << "plus";
197bdd1243dSDimitry Andric     break;
198bdd1243dSDimitry Andric   case dwarf::DW_OP_plus_uconst:
199bdd1243dSDimitry Andric     Stream << "plus_uconst " << unsigned(Operands[0]);
200bdd1243dSDimitry Andric     break;
201bdd1243dSDimitry Andric   case dwarf::DW_OP_shl:
202bdd1243dSDimitry Andric     Stream << "shl";
203bdd1243dSDimitry Andric     break;
204bdd1243dSDimitry Andric   case dwarf::DW_OP_shr:
205bdd1243dSDimitry Andric     Stream << "shr";
206bdd1243dSDimitry Andric     break;
207bdd1243dSDimitry Andric   case dwarf::DW_OP_shra:
208bdd1243dSDimitry Andric     Stream << "shra";
209bdd1243dSDimitry Andric     break;
210bdd1243dSDimitry Andric   case dwarf::DW_OP_xor:
211bdd1243dSDimitry Andric     Stream << "xor";
212bdd1243dSDimitry Andric     break;
213bdd1243dSDimitry Andric 
214bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
215bdd1243dSDimitry Andric   // 2.5.1.5 Control Flow Operations.
216bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
217bdd1243dSDimitry Andric   case dwarf::DW_OP_le:
218bdd1243dSDimitry Andric     Stream << "le";
219bdd1243dSDimitry Andric     break;
220bdd1243dSDimitry Andric   case dwarf::DW_OP_ge:
221bdd1243dSDimitry Andric     Stream << "ge";
222bdd1243dSDimitry Andric     break;
223bdd1243dSDimitry Andric   case dwarf::DW_OP_eq:
224bdd1243dSDimitry Andric     Stream << "eq";
225bdd1243dSDimitry Andric     break;
226bdd1243dSDimitry Andric   case dwarf::DW_OP_lt:
227bdd1243dSDimitry Andric     Stream << "lt";
228bdd1243dSDimitry Andric     break;
229bdd1243dSDimitry Andric   case dwarf::DW_OP_gt:
230bdd1243dSDimitry Andric     Stream << "gt";
231bdd1243dSDimitry Andric     break;
232bdd1243dSDimitry Andric   case dwarf::DW_OP_ne:
233bdd1243dSDimitry Andric     Stream << "ne";
234bdd1243dSDimitry Andric     break;
235bdd1243dSDimitry Andric   case dwarf::DW_OP_skip:
236bdd1243dSDimitry Andric     Stream << "skip " << signed(Operands[0]);
237bdd1243dSDimitry Andric     break;
238bdd1243dSDimitry Andric   case dwarf::DW_OP_bra:
239bdd1243dSDimitry Andric     Stream << "bra " << signed(Operands[0]);
240bdd1243dSDimitry Andric     break;
241bdd1243dSDimitry Andric   case dwarf::DW_OP_call2:
242bdd1243dSDimitry Andric     Stream << "call2 DIE offset " << hexString(Operands[0]);
243bdd1243dSDimitry Andric     break;
244bdd1243dSDimitry Andric   case dwarf::DW_OP_call4:
245bdd1243dSDimitry Andric     Stream << "call4 DIE offset " << hexString(Operands[0]);
246bdd1243dSDimitry Andric     break;
247bdd1243dSDimitry Andric   case dwarf::DW_OP_call_ref:
248bdd1243dSDimitry Andric     Stream << "call_ref DIE offset " << hexString(Operands[0]);
249bdd1243dSDimitry Andric     break;
250bdd1243dSDimitry Andric 
251bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
252bdd1243dSDimitry Andric   // 2.5.1.6 Type Conversions.
253bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
254bdd1243dSDimitry Andric   case dwarf::DW_OP_convert:
255bdd1243dSDimitry Andric     Stream << "convert DIE offset " << hexString(Operands[0]);
256bdd1243dSDimitry Andric     break;
257bdd1243dSDimitry Andric   case dwarf::DW_OP_reinterpret:
258bdd1243dSDimitry Andric     Stream << "reinterpret DIE offset " << hexString(Operands[0]);
259bdd1243dSDimitry Andric     break;
260bdd1243dSDimitry Andric 
261bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
262bdd1243dSDimitry Andric   // 2.5.1.7 Special Operations.
263bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
264bdd1243dSDimitry Andric   case dwarf::DW_OP_nop:
265bdd1243dSDimitry Andric     Stream << "nop";
266bdd1243dSDimitry Andric     break;
267bdd1243dSDimitry Andric   case dwarf::DW_OP_entry_value:
268bdd1243dSDimitry Andric     Stream << "TODO: DW_OP_entry_value";
269bdd1243dSDimitry Andric     break;
270bdd1243dSDimitry Andric 
271bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
272bdd1243dSDimitry Andric   // 2.6.1.1.3 Register location descriptions.
273bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
274bdd1243dSDimitry Andric   case dwarf::DW_OP_regx:
275bdd1243dSDimitry Andric     Stream << "regx" << getReader().getRegisterName(Opcode, Operands);
276bdd1243dSDimitry Andric     break;
277bdd1243dSDimitry Andric 
278bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
279bdd1243dSDimitry Andric   // 2.6.1.1.4 Implicit location descriptions.
280bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
281bdd1243dSDimitry Andric   case dwarf::DW_OP_stack_value:
282bdd1243dSDimitry Andric     Stream << "stack_value";
283bdd1243dSDimitry Andric     break;
284bdd1243dSDimitry Andric   case dwarf::DW_OP_implicit_value:
285bdd1243dSDimitry Andric     Stream << "TODO: DW_OP_implicit_value";
286bdd1243dSDimitry Andric     break;
287bdd1243dSDimitry Andric   case dwarf::DW_OP_implicit_pointer:
288bdd1243dSDimitry Andric     Stream << "implicit_pointer DIE offset " << hexString(Operands[0]) << " "
289bdd1243dSDimitry Andric            << int(Operands[1]);
290bdd1243dSDimitry Andric     break;
291bdd1243dSDimitry Andric 
292bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
293bdd1243dSDimitry Andric   // 2.6.1.2 Composite location descriptions.
294bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
295bdd1243dSDimitry Andric   case dwarf::DW_OP_piece:
296bdd1243dSDimitry Andric     Stream << "piece " << int(Operands[0]);
297bdd1243dSDimitry Andric     break;
298bdd1243dSDimitry Andric   case dwarf::DW_OP_bit_piece:
299bdd1243dSDimitry Andric     Stream << "bit_piece " << int(Operands[0]) << " offset "
300bdd1243dSDimitry Andric            << int(Operands[1]);
301bdd1243dSDimitry Andric     break;
302bdd1243dSDimitry Andric 
303bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
304bdd1243dSDimitry Andric   // GNU extensions.
305bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
306bdd1243dSDimitry Andric   case dwarf::DW_OP_GNU_entry_value:
307bdd1243dSDimitry Andric     Stream << "gnu_entry_value ";
308bdd1243dSDimitry Andric     PrintRegisterInfo(dwarf::DW_OP_reg0);
309bdd1243dSDimitry Andric     break;
310bdd1243dSDimitry Andric   case dwarf::DW_OP_GNU_push_tls_address:
311bdd1243dSDimitry Andric     Stream << "gnu_push_tls_address " << hexString(Operands[0]);
312bdd1243dSDimitry Andric     break;
313bdd1243dSDimitry Andric   case dwarf::DW_OP_GNU_addr_index:
314bdd1243dSDimitry Andric     Stream << "gnu_addr_index " << unsigned(Operands[0]);
315bdd1243dSDimitry Andric     break;
316bdd1243dSDimitry Andric   case dwarf::DW_OP_GNU_const_index:
317bdd1243dSDimitry Andric     Stream << "gnu_const_index " << unsigned(Operands[0]);
318bdd1243dSDimitry Andric     break;
319bdd1243dSDimitry Andric 
320bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
321bdd1243dSDimitry Andric   // Member location.
322bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
323bdd1243dSDimitry Andric   case LVLocationMemberOffset:
324bdd1243dSDimitry Andric     Stream << "offset " << int(Operands[0]);
325bdd1243dSDimitry Andric     break;
326bdd1243dSDimitry Andric 
327bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
328bdd1243dSDimitry Andric   // Missing location.
329bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
330bdd1243dSDimitry Andric   case dwarf::DW_OP_hi_user:
331bdd1243dSDimitry Andric     Stream << "missing";
332bdd1243dSDimitry Andric     break;
333bdd1243dSDimitry Andric 
334bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
335bdd1243dSDimitry Andric   // Register values.
336bdd1243dSDimitry Andric   //-------------------------------------------------------------------------
337bdd1243dSDimitry Andric   default:
338bdd1243dSDimitry Andric     PrintRegisterInfo(Opcode);
339bdd1243dSDimitry Andric     break;
340bdd1243dSDimitry Andric   }
341bdd1243dSDimitry Andric 
342bdd1243dSDimitry Andric   return String;
343bdd1243dSDimitry Andric }
344bdd1243dSDimitry Andric 
345bdd1243dSDimitry Andric // Identify the most common type of operations and print them using a high
346bdd1243dSDimitry Andric // level format, trying to isolate the CodeView complexity.
getOperandsCodeViewInfo()347bdd1243dSDimitry Andric std::string LVOperation::getOperandsCodeViewInfo() {
348bdd1243dSDimitry Andric   std::string String;
349bdd1243dSDimitry Andric   raw_string_ostream Stream(String);
350bdd1243dSDimitry Andric 
351bdd1243dSDimitry Andric   // Get original CodeView operation code.
352bdd1243dSDimitry Andric   uint16_t OperationCode = getCodeViewOperationCode(Opcode);
353bdd1243dSDimitry Andric 
354bdd1243dSDimitry Andric   switch (OperationCode) {
355*06c3fb27SDimitry Andric   // Operands: [Offset].
356bdd1243dSDimitry Andric   case codeview::SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL:
357bdd1243dSDimitry Andric     Stream << "frame_pointer_rel " << int(Operands[0]);
358bdd1243dSDimitry Andric     break;
359bdd1243dSDimitry Andric   case codeview::SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:
360bdd1243dSDimitry Andric     Stream << "frame_pointer_rel_full_scope " << int(Operands[0]);
361bdd1243dSDimitry Andric     break;
362bdd1243dSDimitry Andric 
363*06c3fb27SDimitry Andric   // Operands: [Register].
364bdd1243dSDimitry Andric   case codeview::SymbolKind::S_DEFRANGE_REGISTER:
365bdd1243dSDimitry Andric     Stream << "register " << getReader().getRegisterName(Opcode, Operands);
366bdd1243dSDimitry Andric     break;
367bdd1243dSDimitry Andric   case codeview::SymbolKind::S_DEFRANGE_SUBFIELD_REGISTER:
368bdd1243dSDimitry Andric     Stream << "subfield_register "
369bdd1243dSDimitry Andric            << getReader().getRegisterName(Opcode, Operands);
370bdd1243dSDimitry Andric     break;
371bdd1243dSDimitry Andric 
372bdd1243dSDimitry Andric   // Operands: [Register, Offset].
373bdd1243dSDimitry Andric   case codeview::SymbolKind::S_DEFRANGE_REGISTER_REL:
374bdd1243dSDimitry Andric     Stream << "register_rel " << getReader().getRegisterName(Opcode, Operands)
375bdd1243dSDimitry Andric            << " offset " << int(Operands[1]);
376bdd1243dSDimitry Andric     break;
377bdd1243dSDimitry Andric 
378*06c3fb27SDimitry Andric   // Operands: [Program].
379bdd1243dSDimitry Andric   case codeview::SymbolKind::S_DEFRANGE:
380bdd1243dSDimitry Andric     Stream << "frame " << int(Operands[0]);
381bdd1243dSDimitry Andric     break;
382bdd1243dSDimitry Andric   case codeview::SymbolKind::S_DEFRANGE_SUBFIELD:
383bdd1243dSDimitry Andric     Stream << "subfield " << int(Operands[0]);
384bdd1243dSDimitry Andric     break;
385bdd1243dSDimitry Andric 
386bdd1243dSDimitry Andric   default:
387bdd1243dSDimitry Andric     Stream << format("#0x%02x: ", Opcode) << hexString(Operands[0]) << " "
388bdd1243dSDimitry Andric            << hexString(Operands[1]) << "#";
389bdd1243dSDimitry Andric     break;
390bdd1243dSDimitry Andric   }
391bdd1243dSDimitry Andric 
392bdd1243dSDimitry Andric   return String;
393bdd1243dSDimitry Andric }
394bdd1243dSDimitry Andric 
395bdd1243dSDimitry Andric namespace {
396bdd1243dSDimitry Andric const char *const KindBaseClassOffset = "BaseClassOffset";
397bdd1243dSDimitry Andric const char *const KindBaseClassStep = "BaseClassStep";
398bdd1243dSDimitry Andric const char *const KindClassOffset = "ClassOffset";
399bdd1243dSDimitry Andric const char *const KindFixedAddress = "FixedAddress";
400bdd1243dSDimitry Andric const char *const KindMissingInfo = "Missing";
401bdd1243dSDimitry Andric const char *const KindOperation = "Operation";
402bdd1243dSDimitry Andric const char *const KindOperationList = "OperationList";
403bdd1243dSDimitry Andric const char *const KindRegister = "Register";
404bdd1243dSDimitry Andric const char *const KindUndefined = "Undefined";
405bdd1243dSDimitry Andric } // end anonymous namespace
406bdd1243dSDimitry Andric 
407bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
408bdd1243dSDimitry Andric // DWARF location information.
409bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
kind() const410bdd1243dSDimitry Andric const char *LVLocation::kind() const {
411bdd1243dSDimitry Andric   const char *Kind = KindUndefined;
412bdd1243dSDimitry Andric   if (getIsBaseClassOffset())
413bdd1243dSDimitry Andric     Kind = KindBaseClassOffset;
414bdd1243dSDimitry Andric   else if (getIsBaseClassStep())
415bdd1243dSDimitry Andric     Kind = KindBaseClassStep;
416bdd1243dSDimitry Andric   else if (getIsClassOffset())
417bdd1243dSDimitry Andric     Kind = KindClassOffset;
418bdd1243dSDimitry Andric   else if (getIsFixedAddress())
419bdd1243dSDimitry Andric     Kind = KindFixedAddress;
420bdd1243dSDimitry Andric   else if (getIsGapEntry())
421bdd1243dSDimitry Andric     Kind = KindMissingInfo;
422bdd1243dSDimitry Andric   else if (getIsOperation())
423bdd1243dSDimitry Andric     Kind = KindOperation;
424bdd1243dSDimitry Andric   else if (getIsOperationList())
425bdd1243dSDimitry Andric     Kind = KindOperationList;
426bdd1243dSDimitry Andric   else if (getIsRegister())
427bdd1243dSDimitry Andric     Kind = KindRegister;
428bdd1243dSDimitry Andric   return Kind;
429bdd1243dSDimitry Andric }
430bdd1243dSDimitry Andric 
getIntervalInfo() const431bdd1243dSDimitry Andric std::string LVLocation::getIntervalInfo() const {
432bdd1243dSDimitry Andric   static const char *const Question = "?";
433bdd1243dSDimitry Andric   std::string String;
434bdd1243dSDimitry Andric   raw_string_ostream Stream(String);
435bdd1243dSDimitry Andric   if (getIsAddressRange())
436bdd1243dSDimitry Andric     Stream << "{Range}";
437bdd1243dSDimitry Andric 
438bdd1243dSDimitry Andric   auto PrintLine = [&](const LVLine *Line) {
439bdd1243dSDimitry Andric     if (Line) {
440bdd1243dSDimitry Andric       std::string TheLine;
441bdd1243dSDimitry Andric       TheLine = Line->lineNumberAsStringStripped();
442bdd1243dSDimitry Andric       Stream << TheLine.c_str();
443bdd1243dSDimitry Andric     } else {
444bdd1243dSDimitry Andric       Stream << Question;
445bdd1243dSDimitry Andric     }
446bdd1243dSDimitry Andric   };
447bdd1243dSDimitry Andric 
448bdd1243dSDimitry Andric   Stream << " Lines ";
449bdd1243dSDimitry Andric   PrintLine(getLowerLine());
450bdd1243dSDimitry Andric   Stream << ":";
451bdd1243dSDimitry Andric   PrintLine(getUpperLine());
452bdd1243dSDimitry Andric 
453bdd1243dSDimitry Andric   if (options().getAttributeOffset())
454bdd1243dSDimitry Andric     // Print the active range (low pc and high pc).
455bdd1243dSDimitry Andric     Stream << " [" << hexString(getLowerAddress()) << ":"
456bdd1243dSDimitry Andric            << hexString(getUpperAddress()) << "]";
457bdd1243dSDimitry Andric 
458bdd1243dSDimitry Andric   return String;
459bdd1243dSDimitry Andric }
460bdd1243dSDimitry Andric 
461bdd1243dSDimitry Andric // Validate the ranges associated with the location.
validateRanges()462bdd1243dSDimitry Andric bool LVLocation::validateRanges() {
463bdd1243dSDimitry Andric   // Traverse the locations and validate them against the address to line
464bdd1243dSDimitry Andric   // mapping in the current compile unit. Record those invalid ranges.
465bdd1243dSDimitry Andric   // A valid range must meet the following conditions:
466bdd1243dSDimitry Andric   // a) line(lopc) <= line(hipc)
467bdd1243dSDimitry Andric   // b) line(lopc) and line(hipc) are valid.
468bdd1243dSDimitry Andric 
469bdd1243dSDimitry Andric   if (!hasAssociatedRange())
470bdd1243dSDimitry Andric     return true;
471bdd1243dSDimitry Andric 
472bdd1243dSDimitry Andric   LVLineRange Range = getReaderCompileUnit()->lineRange(this);
473bdd1243dSDimitry Andric   LVLine *LowLine = Range.first;
474bdd1243dSDimitry Andric   LVLine *HighLine = Range.second;
475bdd1243dSDimitry Andric   if (LowLine)
476bdd1243dSDimitry Andric     setLowerLine(LowLine);
477bdd1243dSDimitry Andric   else {
478bdd1243dSDimitry Andric     setIsInvalidLower();
479bdd1243dSDimitry Andric     return false;
480bdd1243dSDimitry Andric   }
481bdd1243dSDimitry Andric   if (HighLine)
482bdd1243dSDimitry Andric     setUpperLine(HighLine);
483bdd1243dSDimitry Andric   else {
484bdd1243dSDimitry Andric     setIsInvalidUpper();
485bdd1243dSDimitry Andric     return false;
486bdd1243dSDimitry Andric   }
487bdd1243dSDimitry Andric   // Check for a valid interval.
488bdd1243dSDimitry Andric   if (LowLine->getLineNumber() > HighLine->getLineNumber()) {
489bdd1243dSDimitry Andric     setIsInvalidRange();
490bdd1243dSDimitry Andric     return false;
491bdd1243dSDimitry Andric   }
492bdd1243dSDimitry Andric 
493bdd1243dSDimitry Andric   return true;
494bdd1243dSDimitry Andric }
495bdd1243dSDimitry Andric 
calculateCoverage(LVLocations * Locations,unsigned & Factor,float & Percentage)496bdd1243dSDimitry Andric bool LVLocation::calculateCoverage(LVLocations *Locations, unsigned &Factor,
497bdd1243dSDimitry Andric                                    float &Percentage) {
498bdd1243dSDimitry Andric   if (!options().getAttributeCoverage() && !Locations)
499bdd1243dSDimitry Andric     return false;
500bdd1243dSDimitry Andric 
501bdd1243dSDimitry Andric   // Calculate the coverage depending on the kind of location. We have
502bdd1243dSDimitry Andric   // the simple and composed locations.
503bdd1243dSDimitry Andric   if (Locations->size() == 1) {
504bdd1243dSDimitry Andric     // Simple: fixed address, class offset, stack offset.
505bdd1243dSDimitry Andric     LVLocation *Location = Locations->front();
506bdd1243dSDimitry Andric     // Some types of locations do not have specific kind. Now is the time
507bdd1243dSDimitry Andric     // to set those types, depending on the operation type.
508bdd1243dSDimitry Andric     Location->updateKind();
509bdd1243dSDimitry Andric     if (Location->getIsLocationSimple()) {
510bdd1243dSDimitry Andric       Factor = 100;
511bdd1243dSDimitry Andric       Percentage = 100;
512bdd1243dSDimitry Andric       return true;
513bdd1243dSDimitry Andric     }
514bdd1243dSDimitry Andric   }
515bdd1243dSDimitry Andric 
516bdd1243dSDimitry Andric   // Composed locations.
517bdd1243dSDimitry Andric   LVAddress LowerAddress = 0;
518bdd1243dSDimitry Andric   LVAddress UpperAddress = 0;
519bdd1243dSDimitry Andric   for (const LVLocation *Location : *Locations)
520bdd1243dSDimitry Andric     // Do not include locations representing a gap.
521bdd1243dSDimitry Andric     if (!Location->getIsGapEntry()) {
522bdd1243dSDimitry Andric       LowerAddress = Location->getLowerAddress();
523bdd1243dSDimitry Andric       UpperAddress = Location->getUpperAddress();
524bdd1243dSDimitry Andric       Factor += (UpperAddress > LowerAddress) ? UpperAddress - LowerAddress
525bdd1243dSDimitry Andric                                               : LowerAddress - UpperAddress;
526bdd1243dSDimitry Andric     }
527bdd1243dSDimitry Andric 
528bdd1243dSDimitry Andric   Percentage = 0;
529bdd1243dSDimitry Andric   return false;
530bdd1243dSDimitry Andric }
531bdd1243dSDimitry Andric 
printRaw(raw_ostream & OS,bool Full) const532bdd1243dSDimitry Andric void LVLocation::printRaw(raw_ostream &OS, bool Full) const {
533bdd1243dSDimitry Andric   // Print the active range (low pc and high pc).
534bdd1243dSDimitry Andric   OS << " [" << hexString(getLowerAddress()) << ":"
535bdd1243dSDimitry Andric      << hexString(getUpperAddress()) << "]\n";
536bdd1243dSDimitry Andric   // Print any DWARF operations.
537bdd1243dSDimitry Andric   printRawExtra(OS, Full);
538bdd1243dSDimitry Andric }
539bdd1243dSDimitry Andric 
printInterval(raw_ostream & OS,bool Full) const540bdd1243dSDimitry Andric void LVLocation::printInterval(raw_ostream &OS, bool Full) const {
541bdd1243dSDimitry Andric   if (hasAssociatedRange())
542bdd1243dSDimitry Andric     OS << getIntervalInfo();
543bdd1243dSDimitry Andric }
544bdd1243dSDimitry Andric 
print(raw_ostream & OS,bool Full) const545bdd1243dSDimitry Andric void LVLocation::print(raw_ostream &OS, bool Full) const {
546bdd1243dSDimitry Andric   if (getReader().doPrintLocation(this)) {
547bdd1243dSDimitry Andric     LVObject::print(OS, Full);
548bdd1243dSDimitry Andric     printExtra(OS, Full);
549bdd1243dSDimitry Andric   }
550bdd1243dSDimitry Andric }
551bdd1243dSDimitry Andric 
printExtra(raw_ostream & OS,bool Full) const552bdd1243dSDimitry Andric void LVLocation::printExtra(raw_ostream &OS, bool Full) const {
553bdd1243dSDimitry Andric   printInterval(OS, Full);
554bdd1243dSDimitry Andric   OS << "\n";
555bdd1243dSDimitry Andric }
556bdd1243dSDimitry Andric 
557bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
558bdd1243dSDimitry Andric // DWARF location for a symbol.
559bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
560bdd1243dSDimitry Andric // Add a Location Entry.
addObject(LVAddress LowPC,LVAddress HighPC,LVUnsigned SectionOffset,uint64_t LocDescOffset)561bdd1243dSDimitry Andric void LVLocationSymbol::addObject(LVAddress LowPC, LVAddress HighPC,
562bdd1243dSDimitry Andric                                  LVUnsigned SectionOffset,
563bdd1243dSDimitry Andric                                  uint64_t LocDescOffset) {
564bdd1243dSDimitry Andric   setLowerAddress(LowPC);
565bdd1243dSDimitry Andric   setUpperAddress(HighPC);
566bdd1243dSDimitry Andric 
567bdd1243dSDimitry Andric   // Record the offset where the location information begins.
568bdd1243dSDimitry Andric   setOffset(LocDescOffset ? LocDescOffset : SectionOffset);
569bdd1243dSDimitry Andric 
570bdd1243dSDimitry Andric   // A -1 HighPC value, indicates no range.
571bdd1243dSDimitry Andric   if (HighPC == LVAddress(UINT64_MAX))
572bdd1243dSDimitry Andric     setIsDiscardedRange();
573bdd1243dSDimitry Andric 
574bdd1243dSDimitry Andric   // Update the location kind, using the DWARF attribute.
575bdd1243dSDimitry Andric   setKind();
576bdd1243dSDimitry Andric }
577bdd1243dSDimitry Andric 
578bdd1243dSDimitry Andric // Add a Location Record.
addObject(LVSmall Opcode,ArrayRef<LVUnsigned> Operands)579*06c3fb27SDimitry Andric void LVLocationSymbol::addObject(LVSmall Opcode,
580*06c3fb27SDimitry Andric                                  ArrayRef<LVUnsigned> Operands) {
581bdd1243dSDimitry Andric   if (!Entries)
582*06c3fb27SDimitry Andric     Entries = std::make_unique<LVOperations>();
583*06c3fb27SDimitry Andric   Entries->push_back(getReader().createOperation(Opcode, Operands));
584bdd1243dSDimitry Andric }
585bdd1243dSDimitry Andric 
586bdd1243dSDimitry Andric // Based on the DWARF attribute, define the location kind.
setKind()587bdd1243dSDimitry Andric void LVLocation::setKind() {
588bdd1243dSDimitry Andric   switch (getAttr()) {
589bdd1243dSDimitry Andric   case dwarf::DW_AT_data_member_location:
590bdd1243dSDimitry Andric     setIsClassOffset();
591bdd1243dSDimitry Andric     break;
592bdd1243dSDimitry Andric   case dwarf::DW_AT_location:
593bdd1243dSDimitry Andric     // Depending on the operand, we have a fixed address.
594bdd1243dSDimitry Andric     setIsFixedAddress();
595bdd1243dSDimitry Andric     break;
596bdd1243dSDimitry Andric   default:
597bdd1243dSDimitry Andric     break;
598bdd1243dSDimitry Andric   }
599bdd1243dSDimitry Andric   // For those symbols with absolute location information, ignore any
600bdd1243dSDimitry Andric   // gaps in their location description; that is the case with absolute
601bdd1243dSDimitry Andric   // memory addresses and members located at specific offsets.
602bdd1243dSDimitry Andric   if (hasAssociatedRange())
603bdd1243dSDimitry Andric     getParentSymbol()->setFillGaps();
604bdd1243dSDimitry Andric }
605bdd1243dSDimitry Andric 
updateKind()606bdd1243dSDimitry Andric void LVLocationSymbol::updateKind() {
607bdd1243dSDimitry Andric   // Update the location type for simple ones.
608bdd1243dSDimitry Andric   if (Entries && Entries->size() == 1) {
609*06c3fb27SDimitry Andric     if (dwarf::DW_OP_fbreg == Entries->front()->getOpcode())
610bdd1243dSDimitry Andric       setIsStackOffset();
611bdd1243dSDimitry Andric   }
612bdd1243dSDimitry Andric }
613bdd1243dSDimitry Andric 
printRawExtra(raw_ostream & OS,bool Full) const614bdd1243dSDimitry Andric void LVLocationSymbol::printRawExtra(raw_ostream &OS, bool Full) const {
615bdd1243dSDimitry Andric   if (Entries)
616bdd1243dSDimitry Andric     for (const LVOperation *Operation : *Entries)
617bdd1243dSDimitry Andric       Operation->print(OS, Full);
618bdd1243dSDimitry Andric }
619bdd1243dSDimitry Andric 
620bdd1243dSDimitry Andric // Print location (formatted version).
print(LVLocations * Locations,raw_ostream & OS,bool Full)621bdd1243dSDimitry Andric void LVLocation::print(LVLocations *Locations, raw_ostream &OS, bool Full) {
622bdd1243dSDimitry Andric   if (!Locations || Locations->empty())
623bdd1243dSDimitry Andric     return;
624bdd1243dSDimitry Andric 
625bdd1243dSDimitry Andric   // Print the symbol coverage.
626bdd1243dSDimitry Andric   if (options().getAttributeCoverage()) {
627bdd1243dSDimitry Andric     // The location entries are contained within a symbol. Get a location,
628bdd1243dSDimitry Andric     // to access basic information about indentation, parent, etc.
629bdd1243dSDimitry Andric     LVLocation *Location = Locations->front();
630bdd1243dSDimitry Andric     LVSymbol *Symbol = Location->getParentSymbol();
631bdd1243dSDimitry Andric     float Percentage = Symbol->getCoveragePercentage();
632bdd1243dSDimitry Andric 
633bdd1243dSDimitry Andric     // The coverage is dependent on the kind of location.
634bdd1243dSDimitry Andric     std::string String;
635bdd1243dSDimitry Andric     raw_string_ostream Stream(String);
636bdd1243dSDimitry Andric     Stream << format("%.2f%%", Percentage);
637bdd1243dSDimitry Andric     if (!Location->getIsLocationSimple())
638bdd1243dSDimitry Andric       Stream << format(" (%d/%d)", Symbol->getCoverageFactor(),
639bdd1243dSDimitry Andric                        Symbol->getParentScope()->getCoverageFactor());
640bdd1243dSDimitry Andric     Symbol->printAttributes(OS, Full, "{Coverage} ", Symbol, StringRef(String),
641bdd1243dSDimitry Andric                             /*UseQuotes=*/false,
642bdd1243dSDimitry Andric                             /*PrintRef=*/false);
643bdd1243dSDimitry Andric   }
644bdd1243dSDimitry Andric 
645bdd1243dSDimitry Andric   // Print the symbol location, including the missing entries.
646bdd1243dSDimitry Andric   if (getReader().doPrintLocation(/*Location=*/nullptr))
647bdd1243dSDimitry Andric     for (const LVLocation *Location : *Locations)
648bdd1243dSDimitry Andric       Location->print(OS, Full);
649bdd1243dSDimitry Andric }
650bdd1243dSDimitry Andric 
printExtra(raw_ostream & OS,bool Full) const651bdd1243dSDimitry Andric void LVLocationSymbol::printExtra(raw_ostream &OS, bool Full) const {
652bdd1243dSDimitry Andric   OS << "{Location}";
653bdd1243dSDimitry Andric   if (getIsCallSite())
654bdd1243dSDimitry Andric     OS << " -> CallSite";
655bdd1243dSDimitry Andric   printInterval(OS, Full);
656bdd1243dSDimitry Andric   OS << "\n";
657bdd1243dSDimitry Andric 
658bdd1243dSDimitry Andric   // Print location entries.
659bdd1243dSDimitry Andric   if (Full && Entries) {
660bdd1243dSDimitry Andric     bool CodeViewLocation = getParentSymbol()->getHasCodeViewLocation();
661bdd1243dSDimitry Andric     std::stringstream Stream;
662*06c3fb27SDimitry Andric     std::string Leading;
663bdd1243dSDimitry Andric     for (LVOperation *Operation : *Entries) {
664bdd1243dSDimitry Andric       Stream << Leading
665bdd1243dSDimitry Andric              << (CodeViewLocation ? Operation->getOperandsCodeViewInfo()
666bdd1243dSDimitry Andric                                   : Operation->getOperandsDWARFInfo());
667bdd1243dSDimitry Andric       Leading = ", ";
668bdd1243dSDimitry Andric     }
669bdd1243dSDimitry Andric     printAttributes(OS, Full, "{Entry} ", const_cast<LVLocationSymbol *>(this),
670bdd1243dSDimitry Andric                     StringRef(Stream.str()),
671bdd1243dSDimitry Andric                     /*UseQuotes=*/false,
672bdd1243dSDimitry Andric                     /*PrintRef=*/false);
673bdd1243dSDimitry Andric   }
674bdd1243dSDimitry Andric }
675