xref: /llvm-project/lldb/source/DataFormatters/FormatterBytecode.cpp (revision ee1adc5aab4fb517314358ce03cfda426da9c4ce)
1 //===-- FormatterBytecode.cpp ---------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "FormatterBytecode.h"
10 #include "lldb/Utility/LLDBLog.h"
11 #include "lldb/ValueObject/ValueObject.h"
12 #include "llvm/ADT/StringExtras.h"
13 #include "llvm/Support/DataExtractor.h"
14 #include "llvm/Support/Format.h"
15 #include "llvm/Support/FormatProviders.h"
16 #include "llvm/Support/FormatVariadicDetails.h"
17 
18 using namespace lldb;
19 namespace lldb_private {
20 
21 std::string toString(FormatterBytecode::OpCodes op) {
22   switch (op) {
23 #define DEFINE_OPCODE(OP, MNEMONIC, NAME)                                      \
24   case OP: {                                                                   \
25     const char *s = MNEMONIC;                                                  \
26     return s ? s : #NAME;                                                      \
27   }
28 #include "FormatterBytecode.def"
29 #undef DEFINE_SIGNATURE
30   }
31   return llvm::utostr(op);
32 }
33 
34 std::string toString(FormatterBytecode::Selectors sel) {
35   switch (sel) {
36 #define DEFINE_SELECTOR(ID, NAME)                                              \
37   case ID:                                                                     \
38     return "@" #NAME;
39 #include "FormatterBytecode.def"
40 #undef DEFINE_SIGNATURE
41   }
42   return "@" + llvm::utostr(sel);
43 }
44 
45 std::string toString(FormatterBytecode::Signatures sig) {
46   switch (sig) {
47 #define DEFINE_SIGNATURE(ID, NAME)                                             \
48   case ID:                                                                     \
49     return "@" #NAME;
50 #include "FormatterBytecode.def"
51 #undef DEFINE_SIGNATURE
52   }
53   return llvm::utostr(sig);
54 }
55 
56 std::string toString(const FormatterBytecode::DataStack &data) {
57   std::string s;
58   llvm::raw_string_ostream os(s);
59   os << "[ ";
60   for (auto &d : data) {
61     if (auto s = std::get_if<std::string>(&d))
62       os << '"' << *s << '"';
63     else if (auto u = std::get_if<uint64_t>(&d))
64       os << *u << 'u';
65     else if (auto i = std::get_if<int64_t>(&d))
66       os << *i;
67     else if (auto valobj = std::get_if<ValueObjectSP>(&d)) {
68       if (!valobj->get())
69         os << "null";
70       else
71         os << "object(" << valobj->get()->GetValueAsCString() << ')';
72     } else if (auto type = std::get_if<CompilerType>(&d)) {
73       os << '(' << type->GetTypeName(true) << ')';
74     } else if (auto sel = std::get_if<FormatterBytecode::Selectors>(&d)) {
75       os << toString(*sel);
76     }
77     os << ' ';
78   }
79   os << ']';
80   return s;
81 }
82 
83 namespace FormatterBytecode {
84 
85 /// Implement the @format function.
86 static llvm::Error FormatImpl(DataStack &data) {
87   auto fmt = data.Pop<std::string>();
88   auto replacements =
89       llvm::formatv_object_base::parseFormatString(fmt, 0, false);
90   std::string s;
91   llvm::raw_string_ostream os(s);
92   unsigned num_args = 0;
93   for (const auto &r : replacements)
94     if (r.Type == llvm::ReplacementType::Format)
95       num_args = std::max(num_args, r.Index + 1);
96 
97   if (data.size() < num_args)
98     return llvm::createStringError("not enough arguments");
99 
100   for (const auto &r : replacements) {
101     if (r.Type == llvm::ReplacementType::Literal) {
102       os << r.Spec;
103       continue;
104     }
105     using namespace llvm::support::detail;
106     auto arg = data[data.size() - num_args + r.Index];
107     auto format = [&](format_adapter &&adapter) {
108       llvm::FmtAlign Align(adapter, r.Where, r.Width, r.Pad);
109       Align.format(os, r.Options);
110     };
111 
112     if (auto s = std::get_if<std::string>(&arg))
113       format(build_format_adapter(s->c_str()));
114     else if (auto u = std::get_if<uint64_t>(&arg))
115       format(build_format_adapter(u));
116     else if (auto i = std::get_if<int64_t>(&arg))
117       format(build_format_adapter(i));
118     else if (auto valobj = std::get_if<ValueObjectSP>(&arg)) {
119       if (!valobj->get())
120         format(build_format_adapter("null object"));
121       else
122         format(build_format_adapter(valobj->get()->GetValueAsCString()));
123     } else if (auto type = std::get_if<CompilerType>(&arg))
124       format(build_format_adapter(type->GetDisplayTypeName()));
125     else if (auto sel = std::get_if<FormatterBytecode::Selectors>(&arg))
126       format(build_format_adapter(toString(*sel)));
127   }
128   data.Push(s);
129   return llvm::Error::success();
130 }
131 
132 static llvm::Error TypeCheck(llvm::ArrayRef<DataStackElement> data,
133                              DataType type) {
134   if (data.size() < 1)
135     return llvm::createStringError("not enough elements on data stack");
136 
137   auto &elem = data.back();
138   switch (type) {
139   case Any:
140     break;
141   case String:
142     if (!std::holds_alternative<std::string>(elem))
143       return llvm::createStringError("expected String");
144     break;
145   case UInt:
146     if (!std::holds_alternative<uint64_t>(elem))
147       return llvm::createStringError("expected UInt");
148     break;
149   case Int:
150     if (!std::holds_alternative<int64_t>(elem))
151       return llvm::createStringError("expected Int");
152     break;
153   case Object:
154     if (!std::holds_alternative<ValueObjectSP>(elem))
155       return llvm::createStringError("expected Object");
156     break;
157   case Type:
158     if (!std::holds_alternative<CompilerType>(elem))
159       return llvm::createStringError("expected Type");
160     break;
161   case Selector:
162     if (!std::holds_alternative<Selectors>(elem))
163       return llvm::createStringError("expected Selector");
164     break;
165   }
166   return llvm::Error::success();
167 }
168 
169 static llvm::Error TypeCheck(llvm::ArrayRef<DataStackElement> data,
170                              DataType type1, DataType type2) {
171   if (auto error = TypeCheck(data, type2))
172     return error;
173   return TypeCheck(data.drop_back(), type1);
174 }
175 
176 static llvm::Error TypeCheck(llvm::ArrayRef<DataStackElement> data,
177                              DataType type1, DataType type2, DataType type3) {
178   if (auto error = TypeCheck(data, type3))
179     return error;
180   return TypeCheck(data.drop_back(1), type2, type1);
181 }
182 
183 llvm::Error Interpret(std::vector<ControlStackElement> &control,
184                       DataStack &data, Selectors sel) {
185   if (control.empty())
186     return llvm::Error::success();
187   // Since the only data types are single endian and ULEBs, the
188   // endianness should not matter.
189   llvm::DataExtractor cur_block(control.back(), true, 64);
190   llvm::DataExtractor::Cursor pc(0);
191 
192   while (!control.empty()) {
193     /// Activate the top most block from the control stack.
194     auto activate_block = [&]() {
195       // Save the return address.
196       if (control.size() > 1)
197         control[control.size() - 2] = cur_block.getData().drop_front(pc.tell());
198       cur_block = llvm::DataExtractor(control.back(), true, 64);
199       if (pc)
200         pc = llvm::DataExtractor::Cursor(0);
201     };
202 
203     /// Fetch the next byte in the instruction stream.
204     auto next_byte = [&]() -> uint8_t {
205       // At the end of the current block?
206       while (pc.tell() >= cur_block.size() && !control.empty()) {
207         if (control.size() == 1) {
208           control.pop_back();
209           return 0;
210         }
211         control.pop_back();
212         activate_block();
213       }
214 
215       // Fetch the next instruction.
216       return cur_block.getU8(pc);
217     };
218 
219     // Fetch the next opcode.
220     OpCodes opcode = (OpCodes)next_byte();
221     if (control.empty() || !pc)
222       return pc.takeError();
223 
224     LLDB_LOGV(GetLog(LLDBLog::DataFormatters),
225               "[eval {0}] opcode={1}, control={2}, data={3}", toString(sel),
226               toString(opcode), control.size(), toString(data));
227 
228     // Various shorthands to improve the readability of error handling.
229 #define TYPE_CHECK(...)                                                        \
230   if (auto error = TypeCheck(data, __VA_ARGS__))                               \
231     return error;
232 
233     auto error = [&](llvm::Twine msg) {
234       return llvm::createStringError(msg + "(opcode=" + toString(opcode) + ")");
235     };
236 
237     switch (opcode) {
238     // Data stack manipulation.
239     case op_dup:
240       TYPE_CHECK(Any);
241       data.Push(data.back());
242       continue;
243     case op_drop:
244       TYPE_CHECK(Any);
245       data.pop_back();
246       continue;
247     case op_pick: {
248       TYPE_CHECK(UInt);
249       uint64_t idx = data.Pop<uint64_t>();
250       if (idx >= data.size())
251         return error("index out of bounds");
252       data.Push(data[idx]);
253       continue;
254     }
255     case op_over:
256       TYPE_CHECK(Any, Any);
257       data.Push(data[data.size() - 2]);
258       continue;
259     case op_swap: {
260       TYPE_CHECK(Any, Any);
261       auto x = data.PopAny();
262       auto y = data.PopAny();
263       data.Push(x);
264       data.Push(y);
265       continue;
266     }
267     case op_rot: {
268       TYPE_CHECK(Any, Any, Any);
269       auto z = data.PopAny();
270       auto y = data.PopAny();
271       auto x = data.PopAny();
272       data.Push(z);
273       data.Push(x);
274       data.Push(y);
275       continue;
276     }
277 
278     // Control stack manipulation.
279     case op_begin: {
280       uint64_t length = cur_block.getULEB128(pc);
281       if (!pc)
282         return pc.takeError();
283       llvm::StringRef block = cur_block.getBytes(pc, length);
284       if (!pc)
285         return pc.takeError();
286       control.push_back(block);
287       continue;
288     }
289     case op_if:
290       TYPE_CHECK(UInt);
291       if (data.Pop<uint64_t>() != 0) {
292         if (!cur_block.size())
293           return error("empty control stack");
294         activate_block();
295       } else
296         control.pop_back();
297       continue;
298     case op_ifelse:
299       TYPE_CHECK(UInt);
300       if (cur_block.size() < 2)
301         return error("empty control stack");
302       if (data.Pop<uint64_t>() == 0)
303         control[control.size() - 2] = control.back();
304       control.pop_back();
305       activate_block();
306       continue;
307     case op_return:
308       control.clear();
309       return pc.takeError();
310 
311     // Literals.
312     case op_lit_uint:
313       data.Push(cur_block.getULEB128(pc));
314       continue;
315     case op_lit_int:
316       data.Push(cur_block.getSLEB128(pc));
317       continue;
318     case op_lit_selector:
319       data.Push(Selectors(cur_block.getU8(pc)));
320       continue;
321     case op_lit_string: {
322       uint64_t length = cur_block.getULEB128(pc);
323       llvm::StringRef bytes = cur_block.getBytes(pc, length);
324       data.Push(bytes.str());
325       continue;
326     }
327     case op_as_uint: {
328       TYPE_CHECK(Int);
329       uint64_t casted;
330       int64_t val = data.Pop<int64_t>();
331       memcpy(&casted, &val, sizeof(val));
332       data.Push(casted);
333       continue;
334     }
335     case op_as_int: {
336       TYPE_CHECK(UInt);
337       int64_t casted;
338       uint64_t val = data.Pop<uint64_t>();
339       memcpy(&casted, &val, sizeof(val));
340       data.Push(casted);
341       continue;
342     }
343     case op_is_null: {
344       TYPE_CHECK(Object);
345       data.Push(data.Pop<ValueObjectSP>() ? (uint64_t)0 : (uint64_t)1);
346       continue;
347     }
348 
349     // Arithmetic, logic, etc.
350 #define BINOP_IMPL(OP, CHECK_ZERO)                                             \
351   {                                                                            \
352     TYPE_CHECK(Any, Any);                                                      \
353     auto y = data.PopAny();                                                    \
354     if (std::holds_alternative<uint64_t>(y)) {                                 \
355       if (CHECK_ZERO && !std::get<uint64_t>(y))                                \
356         return error(#OP " by zero");                                          \
357       TYPE_CHECK(UInt);                                                        \
358       data.Push((uint64_t)(data.Pop<uint64_t>() OP std::get<uint64_t>(y)));    \
359     } else if (std::holds_alternative<int64_t>(y)) {                           \
360       if (CHECK_ZERO && !std::get<int64_t>(y))                                 \
361         return error(#OP " by zero");                                          \
362       TYPE_CHECK(Int);                                                         \
363       data.Push((int64_t)(data.Pop<int64_t>() OP std::get<int64_t>(y)));       \
364     } else                                                                     \
365       return error("unsupported data types");                                  \
366   }
367 #define BINOP(OP) BINOP_IMPL(OP, false)
368 #define BINOP_CHECKZERO(OP) BINOP_IMPL(OP, true)
369     case op_plus:
370       BINOP(+);
371       continue;
372     case op_minus:
373       BINOP(-);
374       continue;
375     case op_mul:
376       BINOP(*);
377       continue;
378     case op_div:
379       BINOP_CHECKZERO(/);
380       continue;
381     case op_mod:
382       BINOP_CHECKZERO(%);
383       continue;
384     case op_shl:
385 #define SHIFTOP(OP, LEFT)                                                      \
386   {                                                                            \
387     TYPE_CHECK(Any, UInt);                                                     \
388     uint64_t y = data.Pop<uint64_t>();                                         \
389     if (y > 64)                                                                \
390       return error("shift out of bounds");                                     \
391     if (std::holds_alternative<uint64_t>(data.back())) {                       \
392       uint64_t x = data.Pop<uint64_t>();                                       \
393       data.Push(x OP y);                                                       \
394     } else if (std::holds_alternative<int64_t>(data.back())) {                 \
395       int64_t x = data.Pop<int64_t>();                                         \
396       if (x < 0 && LEFT)                                                       \
397         return error("left shift of negative value");                          \
398       if (y > 64)                                                              \
399         return error("shift out of bounds");                                   \
400       data.Push(x OP y);                                                       \
401     } else                                                                     \
402       return error("unsupported data types");                                  \
403   }
404       SHIFTOP(<<, true);
405       continue;
406     case op_shr:
407       SHIFTOP(>>, false);
408       continue;
409     case op_and:
410       BINOP(&);
411       continue;
412     case op_or:
413       BINOP(|);
414       continue;
415     case op_xor:
416       BINOP(^);
417       continue;
418     case op_not:
419       TYPE_CHECK(UInt);
420       data.Push(~data.Pop<uint64_t>());
421       continue;
422     case op_eq:
423       BINOP(==);
424       continue;
425     case op_neq:
426       BINOP(!=);
427       continue;
428     case op_lt:
429       BINOP(<);
430       continue;
431     case op_gt:
432       BINOP(>);
433       continue;
434     case op_le:
435       BINOP(<=);
436       continue;
437     case op_ge:
438       BINOP(>=);
439       continue;
440     case op_call: {
441       TYPE_CHECK(Selector);
442       Selectors sel = data.Pop<Selectors>();
443 
444       // Shorthand to improve readability.
445 #define POP_VALOBJ(VALOBJ)                                                     \
446   auto VALOBJ = data.Pop<ValueObjectSP>();                                     \
447   if (!VALOBJ)                                                                 \
448     return error("null object");
449 
450       auto sel_error = [&](const char *msg) {
451         return llvm::createStringError("{0} (opcode={1}, selector={2})", msg,
452                                        toString(opcode).c_str(),
453                                        toString(sel).c_str());
454       };
455 
456       switch (sel) {
457       case sel_summary: {
458         TYPE_CHECK(Object);
459         POP_VALOBJ(valobj);
460         const char *summary = valobj->GetSummaryAsCString();
461         data.Push(summary ? std::string(valobj->GetSummaryAsCString())
462                           : std::string());
463         break;
464       }
465       case sel_get_num_children: {
466         TYPE_CHECK(Object);
467         POP_VALOBJ(valobj);
468         auto result = valobj->GetNumChildren();
469         if (!result)
470           return result.takeError();
471         data.Push((uint64_t)*result);
472         break;
473       }
474       case sel_get_child_at_index: {
475         TYPE_CHECK(Object, UInt);
476         auto index = data.Pop<uint64_t>();
477         POP_VALOBJ(valobj);
478         data.Push(valobj->GetChildAtIndex(index));
479         break;
480       }
481       case sel_get_child_with_name: {
482         TYPE_CHECK(Object, String);
483         auto name = data.Pop<std::string>();
484         POP_VALOBJ(valobj);
485         data.Push(valobj->GetChildMemberWithName(name));
486         break;
487       }
488       case sel_get_child_index: {
489         TYPE_CHECK(Object, String);
490         auto name = data.Pop<std::string>();
491         POP_VALOBJ(valobj);
492         data.Push((uint64_t)valobj->GetIndexOfChildWithName(name));
493         break;
494       }
495       case sel_get_type: {
496         TYPE_CHECK(Object);
497         POP_VALOBJ(valobj);
498         // FIXME: do we need to control dynamic type resolution?
499         data.Push(valobj->GetTypeImpl().GetCompilerType(false));
500         break;
501       }
502       case sel_get_template_argument_type: {
503         TYPE_CHECK(Type, UInt);
504         auto index = data.Pop<uint64_t>();
505         auto type = data.Pop<CompilerType>();
506         // FIXME: There is more code in SBType::GetTemplateArgumentType().
507         data.Push(type.GetTypeTemplateArgument(index, true));
508         break;
509       }
510       case sel_get_value: {
511         TYPE_CHECK(Object);
512         POP_VALOBJ(valobj);
513         data.Push(std::string(valobj->GetValueAsCString()));
514         break;
515       }
516       case sel_get_value_as_unsigned: {
517         TYPE_CHECK(Object);
518         POP_VALOBJ(valobj);
519         bool success;
520         uint64_t val = valobj->GetValueAsUnsigned(0, &success);
521         data.Push(val);
522         if (!success)
523           return sel_error("failed to get value");
524         break;
525       }
526       case sel_get_value_as_signed: {
527         TYPE_CHECK(Object);
528         POP_VALOBJ(valobj);
529         bool success;
530         int64_t val = valobj->GetValueAsSigned(0, &success);
531         data.Push(val);
532         if (!success)
533           return sel_error("failed to get value");
534         break;
535       }
536       case sel_get_value_as_address: {
537         TYPE_CHECK(Object);
538         POP_VALOBJ(valobj);
539         bool success;
540         uint64_t addr = valobj->GetValueAsUnsigned(0, &success);
541         if (!success)
542           return sel_error("failed to get value");
543         if (auto process_sp = valobj->GetProcessSP())
544           addr = process_sp->FixDataAddress(addr);
545         data.Push(addr);
546         break;
547       }
548       case sel_cast: {
549         TYPE_CHECK(Object, Type);
550         auto type = data.Pop<CompilerType>();
551         POP_VALOBJ(valobj);
552         data.Push(valobj->Cast(type));
553         break;
554       }
555       case sel_strlen: {
556         TYPE_CHECK(String);
557         data.Push((uint64_t)data.Pop<std::string>().size());
558         break;
559       }
560       case sel_fmt: {
561         TYPE_CHECK(String);
562         if (auto error = FormatImpl(data))
563           return error;
564         break;
565       }
566       default:
567         return sel_error("selector not implemented");
568       }
569       continue;
570     }
571     }
572     return error("opcode not implemented");
573   }
574   return pc.takeError();
575 }
576 } // namespace FormatterBytecode
577 
578 } // namespace lldb_private
579