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