1 //===-- CommandObjectRegister.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 #include "CommandObjectRegister.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Core/DataExtractor.h"
17 #include "lldb/Core/RegisterValue.h"
18 #include "lldb/Core/Scalar.h"
19 #include "lldb/Core/Debugger.h"
20 #include "lldb/Interpreter/Args.h"
21 #include "lldb/Interpreter/CommandInterpreter.h"
22 #include "lldb/Interpreter/CommandReturnObject.h"
23 #include "lldb/Interpreter/NamedOptionValue.h"
24 #include "lldb/Interpreter/Options.h"
25 #include "lldb/Interpreter/OptionGroupFormat.h"
26 #include "lldb/Target/ExecutionContext.h"
27 #include "lldb/Target/Process.h"
28 #include "lldb/Target/RegisterContext.h"
29 #include "lldb/Target/Thread.h"
30 
31 using namespace lldb;
32 using namespace lldb_private;
33 
34 //----------------------------------------------------------------------
35 // "register read"
36 //----------------------------------------------------------------------
37 class CommandObjectRegisterRead : public CommandObject
38 {
39 public:
40     CommandObjectRegisterRead (CommandInterpreter &interpreter) :
41         CommandObject (interpreter,
42                        "register read",
43                        "Dump the contents of one or more register values from the current frame.  If no register is specified, dumps them all.",
44                        //"register read [<reg-name1> [<reg-name2> [...]]]",
45                        NULL,
46                        eFlagProcessMustBeLaunched | eFlagProcessMustBePaused),
47         m_option_group (interpreter),
48         m_format_options (eFormatDefault),
49         m_command_options ()
50     {
51         CommandArgumentEntry arg;
52         CommandArgumentData register_arg;
53 
54         // Define the first (and only) variant of this arg.
55         register_arg.arg_type = eArgTypeRegisterName;
56         register_arg.arg_repetition = eArgRepeatStar;
57 
58         // There is only one variant this argument could be; put it into the argument entry.
59         arg.push_back (register_arg);
60 
61         // Push the data for the first argument into the m_arguments vector.
62         m_arguments.push_back (arg);
63 
64         // Add the "--format"
65         m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_ALL);
66         m_option_group.Append (&m_command_options);
67         m_option_group.Finalize();
68 
69     }
70 
71     virtual
72     ~CommandObjectRegisterRead ()
73     {
74     }
75 
76     Options *
77     GetOptions ()
78     {
79         return &m_option_group;
80     }
81 
82     bool
83     DumpRegister (const ExecutionContext &exe_ctx,
84                   Stream &strm,
85                   RegisterContext *reg_ctx,
86                   const RegisterInfo *reg_info)
87     {
88         if (reg_info)
89         {
90             RegisterValue reg_value;
91 
92             if (reg_ctx->ReadRegister (reg_info, reg_value))
93             {
94                 strm.Indent ();
95 
96                 bool prefix_with_altname = m_command_options.alternate_name;
97                 bool prefix_with_name = !prefix_with_altname;
98                 reg_value.Dump(&strm, reg_info, prefix_with_name, prefix_with_altname, m_format_options.GetFormat());
99                 if (((reg_info->encoding == eEncodingUint) || (reg_info->encoding == eEncodingSint)) &&
100                     (reg_info->byte_size == reg_ctx->GetThread().GetProcess().GetAddressByteSize()))
101                 {
102                     addr_t reg_addr = reg_value.GetAsUInt64(LLDB_INVALID_ADDRESS);
103                     if (reg_addr != LLDB_INVALID_ADDRESS)
104                     {
105                         Address so_reg_addr;
106                         if (exe_ctx.GetTargetRef().GetSectionLoadList().ResolveLoadAddress(reg_addr, so_reg_addr))
107                         {
108                             strm.PutCString ("  ");
109                             so_reg_addr.Dump(&strm, exe_ctx.GetBestExecutionContextScope(), Address::DumpStyleResolvedDescription);
110                         }
111                     }
112                 }
113                 strm.EOL();
114                 return true;
115             }
116         }
117         return false;
118     }
119 
120     bool
121     DumpRegisterSet (const ExecutionContext &exe_ctx,
122                      Stream &strm,
123                      RegisterContext *reg_ctx,
124                      uint32_t set_idx)
125     {
126         uint32_t unavailable_count = 0;
127         uint32_t available_count = 0;
128         const RegisterSet * const reg_set = reg_ctx->GetRegisterSet(set_idx);
129         if (reg_set)
130         {
131             strm.Printf ("%s:\n", reg_set->name);
132             strm.IndentMore ();
133             const uint32_t num_registers = reg_set->num_registers;
134             for (uint32_t reg_idx = 0; reg_idx < num_registers; ++reg_idx)
135             {
136                 const uint32_t reg = reg_set->registers[reg_idx];
137                 if (DumpRegister (exe_ctx, strm, reg_ctx, reg_ctx->GetRegisterInfoAtIndex(reg)))
138                     ++available_count;
139                 else
140                     ++unavailable_count;
141             }
142             strm.IndentLess ();
143             if (unavailable_count)
144             {
145                 strm.Indent ();
146                 strm.Printf("%u registers were unavailable.\n", unavailable_count);
147             }
148             strm.EOL();
149         }
150         return available_count > 0;
151     }
152 
153     virtual bool
154     Execute
155     (
156         Args& command,
157         CommandReturnObject &result
158     )
159     {
160         Stream &strm = result.GetOutputStream();
161         ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
162         RegisterContext *reg_ctx = exe_ctx.GetRegisterContext ();
163 
164         if (reg_ctx)
165         {
166             const RegisterInfo *reg_info = NULL;
167             if (command.GetArgumentCount() == 0)
168             {
169                 uint32_t set_idx;
170 
171                 uint32_t num_register_sets = 1;
172                 const uint32_t set_array_size = m_command_options.set_indexes.GetSize();
173                 if (set_array_size > 0)
174                 {
175                     for (uint32_t i=0; i<set_array_size; ++i)
176                     {
177                         set_idx = m_command_options.set_indexes[i]->GetUInt64Value (UINT32_MAX, NULL);
178                         if (set_idx != UINT32_MAX)
179                         {
180                             if (!DumpRegisterSet (exe_ctx, strm, reg_ctx, set_idx))
181                             {
182                                 result.AppendErrorWithFormat ("invalid register set index: %u\n", set_idx);
183                                 result.SetStatus (eReturnStatusFailed);
184                                 break;
185                             }
186                         }
187                         else
188                         {
189                             result.AppendError ("invalid register set index\n");
190                             result.SetStatus (eReturnStatusFailed);
191                             break;
192                         }
193                     }
194                 }
195                 else
196                 {
197                     if (m_command_options.dump_all_sets)
198                         num_register_sets = reg_ctx->GetRegisterSetCount();
199 
200                     for (set_idx = 0; set_idx < num_register_sets; ++set_idx)
201                     {
202                         DumpRegisterSet (exe_ctx, strm, reg_ctx, set_idx);
203                     }
204                 }
205             }
206             else
207             {
208                 if (m_command_options.dump_all_sets)
209                 {
210                     result.AppendError ("the --all option can't be used when registers names are supplied as arguments\n");
211                     result.SetStatus (eReturnStatusFailed);
212                 }
213                 else if (m_command_options.set_indexes.GetSize() > 0)
214                 {
215                     result.AppendError ("the --set <set> option can't be used when registers names are supplied as arguments\n");
216                     result.SetStatus (eReturnStatusFailed);
217                 }
218                 else
219                 {
220                     const char *arg_cstr;
221                     for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx)
222                     {
223                         reg_info = reg_ctx->GetRegisterInfoByName(arg_cstr);
224 
225                         if (reg_info)
226                         {
227                             if (!DumpRegister (exe_ctx, strm, reg_ctx, reg_info))
228                                 strm.Printf("%-12s = error: unavailable\n", reg_info->name);
229                         }
230                         else
231                         {
232                             result.AppendErrorWithFormat ("Invalid register name '%s'.\n", arg_cstr);
233                         }
234                     }
235                 }
236             }
237         }
238         else
239         {
240             result.AppendError ("no current frame");
241             result.SetStatus (eReturnStatusFailed);
242         }
243         return result.Succeeded();
244     }
245 
246     class CommandOptions : public OptionGroup
247     {
248     public:
249         CommandOptions () :
250             OptionGroup(),
251             set_indexes (OptionValue::ConvertTypeToMask (OptionValue::eTypeUInt64)),
252             dump_all_sets (false, false), // Initial and default values are false
253             alternate_name (false, false)
254         {
255         }
256 
257         virtual
258         ~CommandOptions ()
259         {
260         }
261 
262 
263         virtual uint32_t
264         GetNumDefinitions ();
265 
266         virtual const OptionDefinition*
267         GetDefinitions ()
268         {
269             return g_option_table;
270         }
271 
272         virtual void
273         OptionParsingStarting (CommandInterpreter &interpreter)
274         {
275             set_indexes.Clear();
276             dump_all_sets.Clear();
277             alternate_name.Clear();
278         }
279 
280         virtual Error
281         SetOptionValue (CommandInterpreter &interpreter,
282                         uint32_t option_idx,
283                         const char *option_value)
284         {
285             Error error;
286             const char short_option = (char) g_option_table[option_idx].short_option;
287             switch (short_option)
288             {
289                 case 's':
290                     {
291                         OptionValueSP value_sp (OptionValueUInt64::Create (option_value, error));
292                         if (value_sp)
293                             set_indexes.AppendValue (value_sp);
294                     }
295                     break;
296 
297                 case 'a':
298                     // When we don't use OptionValue::SetValueFromCString(const char *) to
299                     // set an option value, it won't be marked as being set in the options
300                     // so we make a call to let users know the value was set via option
301                     dump_all_sets.SetCurrentValue (true);
302                     dump_all_sets.SetOptionWasSet ();
303                     break;
304 
305                 case 'A':
306                     // When we don't use OptionValue::SetValueFromCString(const char *) to
307                     // set an option value, it won't be marked as being set in the options
308                     // so we make a call to let users know the value was set via option
309                     alternate_name.SetCurrentValue (true);
310                     dump_all_sets.SetOptionWasSet ();
311                     break;
312 
313                 default:
314                     error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
315                     break;
316             }
317             return error;
318         }
319 
320         // Options table: Required for subclasses of Options.
321 
322         static const OptionDefinition g_option_table[];
323 
324         // Instance variables to hold the values for command options.
325         OptionValueArray set_indexes;
326         OptionValueBoolean dump_all_sets;
327         OptionValueBoolean alternate_name;
328     };
329 
330     OptionGroupOptions m_option_group;
331     OptionGroupFormat m_format_options;
332     CommandOptions m_command_options;
333 };
334 
335 const OptionDefinition
336 CommandObjectRegisterRead::CommandOptions::g_option_table[] =
337 {
338     { LLDB_OPT_SET_ALL, false, "alternate", 'A', no_argument      , NULL, 0, eArgTypeNone      , "Display register names using the alternate register name if there is one."},
339     { LLDB_OPT_SET_1  , false, "set"      , 's', required_argument, NULL, 0, eArgTypeIndex     , "Specify which register sets to dump by index."},
340     { LLDB_OPT_SET_2  , false, "all"      , 'a', no_argument      , NULL, 0, eArgTypeNone      , "Show all register sets."},
341 };
342 
343 uint32_t
344 CommandObjectRegisterRead::CommandOptions::GetNumDefinitions ()
345 {
346     return sizeof(g_option_table)/sizeof(OptionDefinition);
347 }
348 
349 
350 //----------------------------------------------------------------------
351 // "register write"
352 //----------------------------------------------------------------------
353 class CommandObjectRegisterWrite : public CommandObject
354 {
355 public:
356     CommandObjectRegisterWrite (CommandInterpreter &interpreter) :
357         CommandObject (interpreter,
358                        "register write",
359                        "Modify a single register value.",
360                        NULL,
361                        eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
362     {
363         CommandArgumentEntry arg1;
364         CommandArgumentEntry arg2;
365         CommandArgumentData register_arg;
366         CommandArgumentData value_arg;
367 
368         // Define the first (and only) variant of this arg.
369         register_arg.arg_type = eArgTypeRegisterName;
370         register_arg.arg_repetition = eArgRepeatPlain;
371 
372         // There is only one variant this argument could be; put it into the argument entry.
373         arg1.push_back (register_arg);
374 
375         // Define the first (and only) variant of this arg.
376         value_arg.arg_type = eArgTypeValue;
377         value_arg.arg_repetition = eArgRepeatPlain;
378 
379         // There is only one variant this argument could be; put it into the argument entry.
380         arg2.push_back (value_arg);
381 
382         // Push the data for the first argument into the m_arguments vector.
383         m_arguments.push_back (arg1);
384         m_arguments.push_back (arg2);
385     }
386 
387     virtual
388     ~CommandObjectRegisterWrite ()
389     {
390     }
391 
392     virtual bool
393     Execute
394     (
395         Args& command,
396         CommandReturnObject &result
397     )
398     {
399         DataExtractor reg_data;
400         ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
401         RegisterContext *reg_ctx = exe_ctx.GetRegisterContext ();
402 
403         if (reg_ctx)
404         {
405             if (command.GetArgumentCount() != 2)
406             {
407                 result.AppendError ("register write takes exactly 2 arguments: <reg-name> <value>");
408                 result.SetStatus (eReturnStatusFailed);
409             }
410             else
411             {
412                 const char *reg_name = command.GetArgumentAtIndex(0);
413                 const char *value_str = command.GetArgumentAtIndex(1);
414                 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
415 
416                 if (reg_info)
417                 {
418                     RegisterValue reg_value;
419 
420                     Error error (reg_value.SetValueFromCString (reg_info, value_str));
421                     if (error.Success())
422                     {
423                         if (reg_ctx->WriteRegister (reg_info, reg_value))
424                         {
425                             result.SetStatus (eReturnStatusSuccessFinishNoResult);
426                             return true;
427                         }
428                     }
429                     if (error.AsCString())
430                     {
431                         result.AppendErrorWithFormat ("Failed to write register '%s' with value '%s': %s\n",
432                                                      reg_name,
433                                                      value_str,
434                                                      error.AsCString());
435                     }
436                     else
437                     {
438                         result.AppendErrorWithFormat ("Failed to write register '%s' with value '%s'",
439                                                      reg_name,
440                                                      value_str);
441                     }
442                     result.SetStatus (eReturnStatusFailed);
443                 }
444                 else
445                 {
446                     result.AppendErrorWithFormat ("Register not found for '%s'.\n", reg_name);
447                     result.SetStatus (eReturnStatusFailed);
448                 }
449             }
450         }
451         else
452         {
453             result.AppendError ("no current frame");
454             result.SetStatus (eReturnStatusFailed);
455         }
456         return result.Succeeded();
457     }
458 };
459 
460 
461 //----------------------------------------------------------------------
462 // CommandObjectRegister constructor
463 //----------------------------------------------------------------------
464 CommandObjectRegister::CommandObjectRegister(CommandInterpreter &interpreter) :
465     CommandObjectMultiword (interpreter,
466                             "register",
467                             "A set of commands to access thread registers.",
468                             "register [read|write] ...")
469 {
470     LoadSubCommand ("read",  CommandObjectSP (new CommandObjectRegisterRead (interpreter)));
471     LoadSubCommand ("write", CommandObjectSP (new CommandObjectRegisterWrite (interpreter)));
472 }
473 
474 
475 //----------------------------------------------------------------------
476 // Destructor
477 //----------------------------------------------------------------------
478 CommandObjectRegister::~CommandObjectRegister()
479 {
480 }
481