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