| 1 | //===-- DumpRegisterInfo.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 "lldb/Core/DumpRegisterInfo.h" |
| 10 | #include "lldb/Target/RegisterContext.h" |
| 11 | #include "lldb/Target/RegisterFlags.h" |
| 12 | #include "lldb/Utility/Stream.h" |
| 13 | |
| 14 | using namespace lldb; |
| 15 | using namespace lldb_private; |
| 16 | |
| 17 | using SetInfo = std::pair<const char *, uint32_t>; |
| 18 | |
| 19 | void lldb_private::DumpRegisterInfo(Stream &strm, RegisterContext &ctx, |
| 20 | const RegisterInfo &info, |
| 21 | uint32_t terminal_width) { |
| 22 | std::vector<const char *> invalidates; |
| 23 | if (info.invalidate_regs) { |
| 24 | for (uint32_t *inv_regs = info.invalidate_regs; |
| 25 | *inv_regs != LLDB_INVALID_REGNUM; ++inv_regs) { |
| 26 | const RegisterInfo *inv_info = |
| 27 | ctx.GetRegisterInfo(reg_kind: lldb::eRegisterKindLLDB, reg_num: *inv_regs); |
| 28 | assert( |
| 29 | inv_info && |
| 30 | "Register invalidate list refers to a register that does not exist." ); |
| 31 | invalidates.push_back(x: inv_info->name); |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | // We include the index here so that you can use it with "register read -s". |
| 36 | std::vector<SetInfo> in_sets; |
| 37 | for (uint32_t set_idx = 0; set_idx < ctx.GetRegisterSetCount(); ++set_idx) { |
| 38 | const RegisterSet *set = ctx.GetRegisterSet(reg_set: set_idx); |
| 39 | assert(set && "Register set should be valid." ); |
| 40 | for (uint32_t reg_idx = 0; reg_idx < set->num_registers; ++reg_idx) { |
| 41 | const RegisterInfo *set_reg_info = |
| 42 | ctx.GetRegisterInfoAtIndex(reg: set->registers[reg_idx]); |
| 43 | assert(set_reg_info && "Register info should be valid." ); |
| 44 | |
| 45 | if (set_reg_info == &info) { |
| 46 | in_sets.push_back(x: {set->name, set_idx}); |
| 47 | break; |
| 48 | } |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | std::vector<const char *> read_from; |
| 53 | if (info.value_regs) { |
| 54 | for (uint32_t *read_regs = info.value_regs; |
| 55 | *read_regs != LLDB_INVALID_REGNUM; ++read_regs) { |
| 56 | const RegisterInfo *read_info = |
| 57 | ctx.GetRegisterInfo(reg_kind: lldb::eRegisterKindLLDB, reg_num: *read_regs); |
| 58 | assert(read_info && "Register value registers list refers to a register " |
| 59 | "that does not exist." ); |
| 60 | read_from.push_back(x: read_info->name); |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | DoDumpRegisterInfo(strm, name: info.name, alt_name: info.alt_name, byte_size: info.byte_size, |
| 65 | invalidates, read_from, in_sets, flags_type: info.flags_type, |
| 66 | terminal_width); |
| 67 | } |
| 68 | |
| 69 | template <typename ElementType> |
| 70 | static void DumpList(Stream &strm, const char *title, |
| 71 | const std::vector<ElementType> &list, |
| 72 | std::function<void(Stream &, ElementType)> emitter) { |
| 73 | if (list.empty()) |
| 74 | return; |
| 75 | |
| 76 | strm.EOL(); |
| 77 | strm << title; |
| 78 | bool first = true; |
| 79 | for (ElementType elem : list) { |
| 80 | if (!first) |
| 81 | strm << ", " ; |
| 82 | first = false; |
| 83 | emitter(strm, elem); |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | void lldb_private::DoDumpRegisterInfo( |
| 88 | Stream &strm, const char *name, const char *alt_name, uint32_t byte_size, |
| 89 | const std::vector<const char *> &invalidates, |
| 90 | const std::vector<const char *> &read_from, |
| 91 | const std::vector<SetInfo> &in_sets, const RegisterFlags *flags_type, |
| 92 | uint32_t terminal_width) { |
| 93 | strm << " Name: " << name; |
| 94 | if (alt_name) |
| 95 | strm << " (" << alt_name << ")" ; |
| 96 | strm.EOL(); |
| 97 | |
| 98 | // Size in bits may seem obvious for the usual 32 or 64 bit registers. |
| 99 | // When we get to vector registers, then scalable vector registers, it is very |
| 100 | // useful to know without the user doing extra work. |
| 101 | strm.Printf(format: " Size: %d bytes (%d bits)" , byte_size, byte_size * 8); |
| 102 | |
| 103 | std::function<void(Stream &, const char *)> emit_str = |
| 104 | [](Stream &strm, const char *s) { strm << s; }; |
| 105 | DumpList(strm, title: "Invalidates: " , list: invalidates, emitter: emit_str); |
| 106 | DumpList(strm, title: " Read from: " , list: read_from, emitter: emit_str); |
| 107 | |
| 108 | std::function<void(Stream &, SetInfo)> emit_set = [](Stream &strm, |
| 109 | SetInfo info) { |
| 110 | strm.Printf(format: "%s (index %d)" , info.first, info.second); |
| 111 | }; |
| 112 | DumpList(strm, title: " In sets: " , list: in_sets, emitter: emit_set); |
| 113 | |
| 114 | if (flags_type) { |
| 115 | strm.Printf(format: "\n\n%s" , flags_type->AsTable(max_width: terminal_width).c_str()); |
| 116 | |
| 117 | std::string enumerators = flags_type->DumpEnums(max_width: terminal_width); |
| 118 | if (enumerators.size()) |
| 119 | strm << "\n\n" << enumerators; |
| 120 | } |
| 121 | } |
| 122 | |