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