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 | |