]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.cpp
Merge OpenSSL 1.0.2l.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Commands / CommandObjectArgs.cpp
1 //===-- CommandObjectArgs.cpp -----------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 // C Includes
11 // C++ Includes
12 // Other libraries and framework includes
13 // Project includes
14 #include "CommandObjectArgs.h"
15 #include "Plugins/ExpressionParser/Clang/ClangExpressionVariable.h"
16 #include "lldb/Core/Debugger.h"
17 #include "lldb/Core/Module.h"
18 #include "lldb/Core/Value.h"
19 #include "lldb/Host/Host.h"
20 #include "lldb/Interpreter/Args.h"
21 #include "lldb/Interpreter/CommandInterpreter.h"
22 #include "lldb/Interpreter/CommandReturnObject.h"
23 #include "lldb/Symbol/ClangASTContext.h"
24 #include "lldb/Symbol/ObjectFile.h"
25 #include "lldb/Symbol/Variable.h"
26 #include "lldb/Target/ABI.h"
27 #include "lldb/Target/Process.h"
28 #include "lldb/Target/StackFrame.h"
29 #include "lldb/Target/Target.h"
30 #include "lldb/Target/Thread.h"
31
32 #include "llvm/ADT/StringSwitch.h"
33
34 using namespace lldb;
35 using namespace lldb_private;
36
37 // This command is a toy.  I'm just using it to have a way to construct the
38 // arguments to
39 // calling functions.
40 //
41
42 static OptionDefinition g_arg_options[] = {
43     // clang-format off
44   { LLDB_OPT_SET_1, false, "debug", 'g', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Enable verbose debug logging of the expression parsing and evaluation." },
45     // clang-format on
46 };
47
48 CommandObjectArgs::CommandOptions::CommandOptions(
49     CommandInterpreter &interpreter)
50     : Options() {
51   // Keep only one place to reset the values to their defaults
52   OptionParsingStarting(nullptr);
53 }
54
55 CommandObjectArgs::CommandOptions::~CommandOptions() = default;
56
57 Error CommandObjectArgs::CommandOptions::SetOptionValue(
58     uint32_t option_idx, llvm::StringRef option_arg,
59     ExecutionContext *execution_context) {
60   Error error;
61
62   const int short_option = m_getopt_table[option_idx].val;
63   error.SetErrorStringWithFormat("invalid short option character '%c'",
64                                  short_option);
65
66   return error;
67 }
68
69 void CommandObjectArgs::CommandOptions::OptionParsingStarting(
70     ExecutionContext *execution_context) {}
71
72 llvm::ArrayRef<OptionDefinition>
73 CommandObjectArgs::CommandOptions::GetDefinitions() {
74   return llvm::makeArrayRef(g_arg_options);
75 }
76
77 CommandObjectArgs::CommandObjectArgs(CommandInterpreter &interpreter)
78     : CommandObjectParsed(interpreter, "args",
79                           "When stopped at the start of a function, reads "
80                           "function arguments of type (u?)int(8|16|32|64)_t, "
81                           "(void|char)*",
82                           "args"),
83       m_options(interpreter) {}
84
85 CommandObjectArgs::~CommandObjectArgs() = default;
86
87 Options *CommandObjectArgs::GetOptions() { return &m_options; }
88
89 bool CommandObjectArgs::DoExecute(Args &args, CommandReturnObject &result) {
90   ConstString target_triple;
91
92   Process *process = m_exe_ctx.GetProcessPtr();
93   if (!process) {
94     result.AppendError("Args found no process.");
95     result.SetStatus(eReturnStatusFailed);
96     return false;
97   }
98
99   const ABI *abi = process->GetABI().get();
100   if (!abi) {
101     result.AppendError("The current process has no ABI.");
102     result.SetStatus(eReturnStatusFailed);
103     return false;
104   }
105
106   if (args.empty()) {
107     result.AppendError("args requires at least one argument");
108     result.SetStatus(eReturnStatusFailed);
109     return false;
110   }
111
112   Thread *thread = m_exe_ctx.GetThreadPtr();
113
114   if (!thread) {
115     result.AppendError("args found no thread.");
116     result.SetStatus(eReturnStatusFailed);
117     return false;
118   }
119
120   lldb::StackFrameSP thread_cur_frame = thread->GetSelectedFrame();
121   if (!thread_cur_frame) {
122     result.AppendError("The current thread has no current frame.");
123     result.SetStatus(eReturnStatusFailed);
124     return false;
125   }
126
127   ModuleSP thread_module_sp(
128       thread_cur_frame->GetFrameCodeAddress().GetModule());
129   if (!thread_module_sp) {
130     result.AppendError("The PC has no associated module.");
131     result.SetStatus(eReturnStatusFailed);
132     return false;
133   }
134
135   TypeSystem *type_system =
136       thread_module_sp->GetTypeSystemForLanguage(eLanguageTypeC);
137   if (type_system == nullptr) {
138     result.AppendError("Unable to create C type system.");
139     result.SetStatus(eReturnStatusFailed);
140     return false;
141   }
142
143   ValueList value_list;
144
145   for (auto &arg_entry : args.entries()) {
146     llvm::StringRef arg_type = arg_entry.ref;
147     Value value;
148     value.SetValueType(Value::eValueTypeScalar);
149     CompilerType compiler_type;
150
151     std::size_t int_pos = arg_type.find("int");
152     if (int_pos != llvm::StringRef::npos) {
153       Encoding encoding = eEncodingSint;
154
155       int width = 0;
156
157       if (int_pos > 1) {
158         result.AppendErrorWithFormat("Invalid format: %s.\n",
159                                      arg_entry.c_str());
160         result.SetStatus(eReturnStatusFailed);
161         return false;
162       }
163       if (int_pos == 1 && arg_type[0] != 'u') {
164         result.AppendErrorWithFormat("Invalid format: %s.\n",
165                                      arg_entry.c_str());
166         result.SetStatus(eReturnStatusFailed);
167         return false;
168       }
169       if (arg_type[0] == 'u') {
170         encoding = eEncodingUint;
171       }
172
173       llvm::StringRef width_spec = arg_type.drop_front(int_pos + 3);
174
175       auto exp_result = llvm::StringSwitch<llvm::Optional<int>>(width_spec)
176                             .Case("8_t", 8)
177                             .Case("16_t", 16)
178                             .Case("32_t", 32)
179                             .Case("64_t", 64)
180                             .Default(llvm::None);
181       if (!exp_result.hasValue()) {
182         result.AppendErrorWithFormat("Invalid format: %s.\n",
183                                      arg_entry.c_str());
184         result.SetStatus(eReturnStatusFailed);
185         return false;
186       }
187       width = *exp_result;
188
189       compiler_type =
190           type_system->GetBuiltinTypeForEncodingAndBitSize(encoding, width);
191
192       if (!compiler_type.IsValid()) {
193         result.AppendErrorWithFormat(
194             "Couldn't get Clang type for format %s (%s integer, width %d).\n",
195             arg_entry.c_str(),
196             (encoding == eEncodingSint ? "signed" : "unsigned"), width);
197
198         result.SetStatus(eReturnStatusFailed);
199         return false;
200       }
201     } else if (arg_type == "void*") {
202       compiler_type =
203           type_system->GetBasicTypeFromAST(eBasicTypeVoid).GetPointerType();
204     } else if (arg_type == "char*") {
205       compiler_type =
206           type_system->GetBasicTypeFromAST(eBasicTypeChar).GetPointerType();
207     } else {
208       result.AppendErrorWithFormat("Invalid format: %s.\n", arg_entry.c_str());
209       result.SetStatus(eReturnStatusFailed);
210       return false;
211     }
212
213     value.SetCompilerType(compiler_type);
214     value_list.PushValue(value);
215   }
216
217   if (!abi->GetArgumentValues(*thread, value_list)) {
218     result.AppendError("Couldn't get argument values");
219     result.SetStatus(eReturnStatusFailed);
220     return false;
221   }
222
223   result.GetOutputStream().Printf("Arguments : \n");
224
225   for (auto entry : llvm::enumerate(args.entries())) {
226     result.GetOutputStream().Printf("%" PRIu64 " (%s): ", (uint64_t)entry.Index,
227                                     entry.Value.c_str());
228     value_list.GetValueAtIndex(entry.Index)->Dump(&result.GetOutputStream());
229     result.GetOutputStream().Printf("\n");
230   }
231
232   return result.Succeeded();
233 }