Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 1 | //===-- CommandObjectMemory.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 "CommandObjectMemory.h" |
| 11 | |
| 12 | // C Includes |
| 13 | // C++ Includes |
| 14 | // Other libraries and framework includes |
| 15 | // Project includes |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 16 | #include "lldb/Core/DataBufferHeap.h" |
| 17 | #include "lldb/Core/DataExtractor.h" |
Greg Clayton | 63094e0 | 2010-06-23 01:19:29 +0000 | [diff] [blame] | 18 | #include "lldb/Core/Debugger.h" |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 19 | #include "lldb/Core/StreamString.h" |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 20 | #include "lldb/Core/ValueObjectMemory.h" |
Greg Clayton | 63094e0 | 2010-06-23 01:19:29 +0000 | [diff] [blame] | 21 | #include "lldb/Interpreter/Args.h" |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 22 | #include "lldb/Interpreter/CommandReturnObject.h" |
Greg Clayton | 63094e0 | 2010-06-23 01:19:29 +0000 | [diff] [blame] | 23 | #include "lldb/Interpreter/CommandInterpreter.h" |
| 24 | #include "lldb/Interpreter/Options.h" |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 25 | #include "lldb/Interpreter/OptionGroupFormat.h" |
| 26 | #include "lldb/Interpreter/OptionGroupOutputFile.h" |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 27 | #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 28 | #include "lldb/Target/Process.h" |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 29 | #include "lldb/Target/StackFrame.h" |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 30 | |
| 31 | using namespace lldb; |
| 32 | using namespace lldb_private; |
| 33 | |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 34 | static OptionDefinition |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 35 | g_option_table[] = |
| 36 | { |
| 37 | { LLDB_OPT_SET_1| |
| 38 | LLDB_OPT_SET_2, false, "size" ,'s', required_argument, NULL, 0, eArgTypeByteSize ,"The size in bytes to use when displaying with the selected format."}, |
| 39 | { LLDB_OPT_SET_1| |
| 40 | LLDB_OPT_SET_3, false, "count" ,'c', required_argument, NULL, 0, eArgTypeCount ,"The number of total items to display."}, |
| 41 | { LLDB_OPT_SET_1, false, "num-per-line" ,'l', required_argument, NULL, 0, eArgTypeNumberPerLine ,"The number of items per line to display."}, |
| 42 | { LLDB_OPT_SET_2, false, "binary" ,'b', no_argument , NULL, 0, eArgTypeNone ,"If true, memory will be saved as binary. If false, the memory is saved save as an ASCII dump that uses the format, size, count and number per line settings."}, |
| 43 | { LLDB_OPT_SET_3, true , "view-as" ,'t', required_argument, NULL, 0, eArgTypeNone ,"The name of a type to view memory as."}, |
| 44 | }; |
| 45 | |
| 46 | |
| 47 | |
| 48 | class OptionGroupReadMemory : public OptionGroup |
| 49 | { |
| 50 | public: |
| 51 | |
| 52 | OptionGroupReadMemory () : |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 53 | m_byte_size (1,1), |
| 54 | m_count (8,8), |
| 55 | m_num_per_line (1,1), |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 56 | m_output_as_binary (false), |
| 57 | m_view_as_type() |
| 58 | { |
| 59 | } |
| 60 | |
| 61 | virtual |
| 62 | ~OptionGroupReadMemory () |
| 63 | { |
| 64 | } |
| 65 | |
| 66 | |
| 67 | virtual uint32_t |
| 68 | GetNumDefinitions () |
| 69 | { |
| 70 | return sizeof (g_option_table) / sizeof (OptionDefinition); |
| 71 | } |
| 72 | |
| 73 | virtual const OptionDefinition* |
| 74 | GetDefinitions () |
| 75 | { |
| 76 | return g_option_table; |
| 77 | } |
| 78 | |
| 79 | virtual Error |
| 80 | SetOptionValue (CommandInterpreter &interpreter, |
| 81 | uint32_t option_idx, |
| 82 | const char *option_arg) |
| 83 | { |
| 84 | Error error; |
| 85 | char short_option = (char) g_option_table[option_idx].short_option; |
| 86 | |
| 87 | switch (short_option) |
| 88 | { |
| 89 | case 'l': |
| 90 | error = m_num_per_line.SetValueFromCString (option_arg); |
| 91 | if (m_num_per_line.GetCurrentValue() == 0) |
| 92 | error.SetErrorStringWithFormat("Invalid value for --num-per-line option '%s'. Must be positive integer value.\n", option_arg); |
| 93 | break; |
| 94 | |
| 95 | case 'c': |
| 96 | error = m_count.SetValueFromCString (option_arg); |
| 97 | if (m_count.GetCurrentValue() == 0) |
| 98 | error.SetErrorStringWithFormat("Invalid value for --count option '%s'. Must be positive integer value.\n", option_arg); |
| 99 | break; |
| 100 | |
| 101 | case 's': |
| 102 | error = m_byte_size.SetValueFromCString (option_arg); |
| 103 | if (m_byte_size.GetCurrentValue() == 0) |
| 104 | error.SetErrorStringWithFormat("Invalid value for --size option '%s'. Must be positive integer value.\n", option_arg); |
| 105 | break; |
| 106 | |
| 107 | case 'b': |
| 108 | m_output_as_binary = true; |
| 109 | break; |
| 110 | |
| 111 | case 't': |
| 112 | error = m_view_as_type.SetValueFromCString (option_arg); |
| 113 | break; |
| 114 | |
| 115 | default: |
| 116 | error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option); |
| 117 | break; |
| 118 | } |
| 119 | return error; |
| 120 | } |
| 121 | |
| 122 | virtual void |
| 123 | OptionParsingStarting (CommandInterpreter &interpreter) |
| 124 | { |
| 125 | m_byte_size.Clear(); |
| 126 | m_count.Clear(); |
| 127 | m_num_per_line.Clear(); |
| 128 | m_output_as_binary = false; |
| 129 | m_view_as_type.Clear(); |
| 130 | } |
| 131 | |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 132 | Error |
| 133 | FinalizeSettings (Target *target, const OptionGroupFormat& format_options) |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 134 | { |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 135 | Error error; |
| 136 | bool byte_size_option_set = m_byte_size.OptionWasSet(); |
| 137 | const bool num_per_line_option_set = m_num_per_line.OptionWasSet(); |
| 138 | const bool count_option_set = m_count.OptionWasSet(); |
| 139 | |
| 140 | uint32_t format_byte_size = format_options.GetByteSize(); |
| 141 | if (byte_size_option_set) |
| 142 | { |
| 143 | if (format_byte_size > 0) |
| 144 | { |
| 145 | error.SetErrorString("can't specify the byte size in both the '--size <num>' option and the '--format [<byte-size>]<format-char>' options."); |
| 146 | return error; |
| 147 | } |
| 148 | } |
| 149 | else |
| 150 | { |
| 151 | if (format_byte_size != 0) |
| 152 | { |
| 153 | byte_size_option_set = true; |
| 154 | m_byte_size = format_byte_size; |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | switch (format_options.GetFormat()) |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 159 | { |
| 160 | default: |
| 161 | break; |
| 162 | |
| 163 | case eFormatBoolean: |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 164 | if (!byte_size_option_set) |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 165 | m_byte_size = 1; |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 166 | if (!num_per_line_option_set) |
| 167 | m_num_per_line = 1; |
| 168 | if (!count_option_set) |
| 169 | m_count = 8; |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 170 | break; |
| 171 | |
| 172 | case eFormatCString: |
| 173 | break; |
| 174 | |
| 175 | case eFormatPointer: |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 176 | m_byte_size = target->GetArchitecture().GetAddressByteSize(); |
| 177 | if (!num_per_line_option_set) |
| 178 | m_num_per_line = 4; |
| 179 | if (!count_option_set) |
| 180 | m_count = 8; |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 181 | break; |
| 182 | |
| 183 | case eFormatBinary: |
| 184 | case eFormatFloat: |
| 185 | case eFormatOctal: |
| 186 | case eFormatDecimal: |
| 187 | case eFormatEnum: |
| 188 | case eFormatUnicode16: |
| 189 | case eFormatUnicode32: |
| 190 | case eFormatUnsigned: |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 191 | if (!byte_size_option_set) |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 192 | m_byte_size = 4; |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 193 | if (!num_per_line_option_set) |
| 194 | m_num_per_line = 1; |
| 195 | if (!count_option_set) |
| 196 | m_count = 8; |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 197 | break; |
| 198 | |
| 199 | case eFormatBytes: |
| 200 | case eFormatBytesWithASCII: |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 201 | if (m_byte_size.OptionWasSet()) |
| 202 | { |
| 203 | if (m_byte_size > 1) |
| 204 | error.SetErrorString ("use --count option to specify an end address to display a number of bytes"); |
| 205 | } |
| 206 | else |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 207 | m_byte_size = 1; |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 208 | if (!num_per_line_option_set) |
| 209 | m_num_per_line = 16; |
| 210 | if (!count_option_set) |
| 211 | m_count = 32; |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 212 | break; |
Greg Clayton | 307fa07 | 2011-06-17 23:50:44 +0000 | [diff] [blame^] | 213 | case eFormatCharArray: |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 214 | case eFormatChar: |
| 215 | case eFormatCharPrintable: |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 216 | if (!byte_size_option_set) |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 217 | m_byte_size = 1; |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 218 | if (!num_per_line_option_set) |
| 219 | m_num_per_line = 32; |
| 220 | if (!count_option_set) |
| 221 | m_count = 64; |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 222 | break; |
| 223 | case eFormatComplex: |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 224 | if (!byte_size_option_set) |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 225 | m_byte_size = 8; |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 226 | if (!num_per_line_option_set) |
| 227 | m_num_per_line = 1; |
| 228 | if (!count_option_set) |
| 229 | m_count = 8; |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 230 | break; |
| 231 | case eFormatHex: |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 232 | if (!byte_size_option_set) |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 233 | m_byte_size = 4; |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 234 | if (!num_per_line_option_set) |
| 235 | { |
| 236 | switch (m_byte_size) |
| 237 | { |
| 238 | case 1: |
| 239 | case 2: |
| 240 | m_num_per_line = 8; |
| 241 | break; |
| 242 | case 4: |
| 243 | m_num_per_line = 4; |
| 244 | break; |
| 245 | case 8: |
| 246 | m_num_per_line = 2; |
| 247 | break; |
| 248 | default: |
| 249 | m_num_per_line = 1; |
| 250 | break; |
| 251 | } |
| 252 | } |
| 253 | if (!count_option_set) |
| 254 | m_count = 8; |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 255 | break; |
| 256 | |
| 257 | case eFormatVectorOfChar: |
| 258 | case eFormatVectorOfSInt8: |
| 259 | case eFormatVectorOfUInt8: |
| 260 | case eFormatVectorOfSInt16: |
| 261 | case eFormatVectorOfUInt16: |
| 262 | case eFormatVectorOfSInt32: |
| 263 | case eFormatVectorOfUInt32: |
| 264 | case eFormatVectorOfSInt64: |
| 265 | case eFormatVectorOfUInt64: |
| 266 | case eFormatVectorOfFloat32: |
| 267 | case eFormatVectorOfFloat64: |
| 268 | case eFormatVectorOfUInt128: |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 269 | if (!byte_size_option_set) |
| 270 | m_byte_size = 128; |
| 271 | if (!num_per_line_option_set) |
| 272 | m_num_per_line = 1; |
| 273 | if (!count_option_set) |
| 274 | m_count = 4; |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 275 | break; |
| 276 | } |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 277 | return error; |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 278 | } |
| 279 | |
| 280 | OptionValueUInt64 m_byte_size; |
| 281 | OptionValueUInt64 m_count; |
| 282 | OptionValueUInt64 m_num_per_line; |
| 283 | bool m_output_as_binary; |
| 284 | OptionValueString m_view_as_type; |
| 285 | }; |
| 286 | |
| 287 | |
| 288 | |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 289 | //---------------------------------------------------------------------- |
| 290 | // Read memory from the inferior process |
| 291 | //---------------------------------------------------------------------- |
| 292 | class CommandObjectMemoryRead : public CommandObject |
| 293 | { |
| 294 | public: |
| 295 | |
Greg Clayton | 238c0a1 | 2010-09-18 01:14:36 +0000 | [diff] [blame] | 296 | CommandObjectMemoryRead (CommandInterpreter &interpreter) : |
| 297 | CommandObject (interpreter, |
| 298 | "memory read", |
Caroline Tice | abb507a | 2010-09-08 21:06:11 +0000 | [diff] [blame] | 299 | "Read from the memory of the process being debugged.", |
Caroline Tice | 43b014a | 2010-10-04 22:28:36 +0000 | [diff] [blame] | 300 | NULL, |
Greg Clayton | f15996e | 2011-04-07 22:46:35 +0000 | [diff] [blame] | 301 | eFlagProcessMustBeLaunched), |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 302 | m_option_group (interpreter), |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 303 | m_format_options (eFormatBytesWithASCII, 0, true), |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 304 | m_memory_options (), |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 305 | m_outfile_options (), |
| 306 | m_varobj_options() |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 307 | { |
Caroline Tice | 43b014a | 2010-10-04 22:28:36 +0000 | [diff] [blame] | 308 | CommandArgumentEntry arg1; |
| 309 | CommandArgumentEntry arg2; |
| 310 | CommandArgumentData start_addr_arg; |
| 311 | CommandArgumentData end_addr_arg; |
| 312 | |
| 313 | // Define the first (and only) variant of this arg. |
| 314 | start_addr_arg.arg_type = eArgTypeStartAddress; |
| 315 | start_addr_arg.arg_repetition = eArgRepeatPlain; |
| 316 | |
| 317 | // There is only one variant this argument could be; put it into the argument entry. |
| 318 | arg1.push_back (start_addr_arg); |
| 319 | |
| 320 | // Define the first (and only) variant of this arg. |
| 321 | end_addr_arg.arg_type = eArgTypeEndAddress; |
| 322 | end_addr_arg.arg_repetition = eArgRepeatOptional; |
| 323 | |
| 324 | // There is only one variant this argument could be; put it into the argument entry. |
| 325 | arg2.push_back (end_addr_arg); |
| 326 | |
| 327 | // Push the data for the first argument into the m_arguments vector. |
| 328 | m_arguments.push_back (arg1); |
| 329 | m_arguments.push_back (arg2); |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 330 | |
| 331 | m_option_group.Append (&m_format_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_3); |
| 332 | m_option_group.Append (&m_memory_options); |
| 333 | m_option_group.Append (&m_outfile_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3); |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 334 | m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3); |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 335 | m_option_group.Finalize(); |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 336 | } |
| 337 | |
| 338 | virtual |
| 339 | ~CommandObjectMemoryRead () |
| 340 | { |
| 341 | } |
| 342 | |
| 343 | Options * |
| 344 | GetOptions () |
| 345 | { |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 346 | return &m_option_group; |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 347 | } |
| 348 | |
| 349 | virtual bool |
Greg Clayton | 238c0a1 | 2010-09-18 01:14:36 +0000 | [diff] [blame] | 350 | Execute (Args& command, |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 351 | CommandReturnObject &result) |
| 352 | { |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 353 | ExecutionContext exe_ctx (m_interpreter.GetExecutionContext()); |
| 354 | if (exe_ctx.process == NULL) |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 355 | { |
| 356 | result.AppendError("need a process to read memory"); |
| 357 | result.SetStatus(eReturnStatusFailed); |
| 358 | return false; |
| 359 | } |
| 360 | const size_t argc = command.GetArgumentCount(); |
| 361 | |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 362 | |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 363 | if (argc == 0 || argc > 2) |
| 364 | { |
| 365 | result.AppendErrorWithFormat ("%s takes 1 or two args.\n", m_cmd_name.c_str()); |
| 366 | result.SetStatus(eReturnStatusFailed); |
| 367 | return false; |
| 368 | } |
| 369 | |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 370 | ClangASTType clang_ast_type; |
| 371 | Error error; |
| 372 | |
| 373 | Format format = m_format_options.GetFormat(); |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 374 | const char *view_as_type_cstr = m_memory_options.m_view_as_type.GetCurrentValue(); |
| 375 | if (view_as_type_cstr && view_as_type_cstr[0]) |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 376 | { |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 377 | // We are viewing memory as a type |
| 378 | SymbolContext sc; |
| 379 | const bool append = true; |
| 380 | TypeList type_list; |
| 381 | uint32_t reference_count = 0; |
| 382 | uint32_t pointer_count = 0; |
| 383 | size_t idx; |
| 384 | static const char *g_keywords[] = { "const", "volatile", "restrict", "struct", "class", "union"}; |
| 385 | static size_t g_num_keywords = sizeof(g_keywords)/sizeof(const char *); |
| 386 | std::string type_str(view_as_type_cstr); |
| 387 | |
| 388 | // Remove all instances of g_keywords that are followed by spaces |
| 389 | for (size_t i = 0; i < g_num_keywords; ++i) |
| 390 | { |
| 391 | const char *keyword = g_keywords[i]; |
| 392 | int keyword_len = ::strlen (keyword); |
| 393 | while ((idx = type_str.find (keyword)) != std::string::npos) |
| 394 | { |
| 395 | if (type_str[idx + keyword_len] == ' ' || type_str[idx + keyword_len] == '\t') |
| 396 | type_str.erase(idx, keyword_len+1); |
| 397 | } |
| 398 | } |
| 399 | bool done = type_str.empty(); |
| 400 | // |
| 401 | idx = type_str.find_first_not_of (" \t"); |
| 402 | if (idx > 0 && idx != std::string::npos) |
| 403 | type_str.erase (0, idx); |
| 404 | while (!done) |
| 405 | { |
| 406 | // Strip trailing spaces |
| 407 | if (type_str.empty()) |
| 408 | done = true; |
| 409 | else |
| 410 | { |
| 411 | switch (type_str[type_str.size()-1]) |
| 412 | { |
| 413 | case '*': |
| 414 | ++pointer_count; |
| 415 | // fall through... |
| 416 | case ' ': |
| 417 | case '\t': |
| 418 | type_str.erase(type_str.size()-1); |
| 419 | break; |
| 420 | |
| 421 | case '&': |
| 422 | if (reference_count == 0) |
| 423 | { |
| 424 | reference_count = 1; |
| 425 | type_str.erase(type_str.size()-1); |
| 426 | } |
| 427 | else |
| 428 | { |
| 429 | result.AppendErrorWithFormat ("invalid type string: '%s'\n", view_as_type_cstr); |
| 430 | result.SetStatus(eReturnStatusFailed); |
| 431 | return false; |
| 432 | } |
| 433 | break; |
| 434 | |
| 435 | default: |
| 436 | done = true; |
| 437 | break; |
| 438 | } |
| 439 | } |
| 440 | } |
| 441 | |
| 442 | ConstString lookup_type_name(type_str.c_str()); |
| 443 | if (exe_ctx.frame) |
| 444 | { |
| 445 | sc = exe_ctx.frame->GetSymbolContext (eSymbolContextModule); |
| 446 | if (sc.module_sp) |
| 447 | { |
| 448 | sc.module_sp->FindTypes (sc, |
| 449 | lookup_type_name, |
| 450 | append, |
| 451 | 1, |
| 452 | type_list); |
| 453 | } |
| 454 | } |
| 455 | if (type_list.GetSize() == 0) |
| 456 | { |
| 457 | exe_ctx.target->GetImages().FindTypes (sc, |
| 458 | lookup_type_name, |
| 459 | append, |
| 460 | 1, |
| 461 | type_list); |
| 462 | } |
| 463 | |
| 464 | if (type_list.GetSize() == 0) |
| 465 | { |
| 466 | result.AppendErrorWithFormat ("unable to find any types that match the raw type '%s' for full type '%s'\n", |
| 467 | lookup_type_name.GetCString(), |
| 468 | view_as_type_cstr); |
| 469 | result.SetStatus(eReturnStatusFailed); |
| 470 | return false; |
| 471 | } |
| 472 | |
| 473 | TypeSP type_sp (type_list.GetTypeAtIndex(0)); |
| 474 | clang_ast_type.SetClangType (type_sp->GetClangAST(), type_sp->GetClangFullType()); |
| 475 | |
| 476 | while (pointer_count > 0) |
| 477 | { |
| 478 | clang_type_t pointer_type = ClangASTContext::CreatePointerType (clang_ast_type.GetASTContext(), clang_ast_type.GetOpaqueQualType()); |
| 479 | if (pointer_type) |
| 480 | clang_ast_type.SetClangType (clang_ast_type.GetASTContext(), pointer_type); |
| 481 | else |
| 482 | { |
| 483 | result.AppendError ("unable make a pointer type\n"); |
| 484 | result.SetStatus(eReturnStatusFailed); |
| 485 | return false; |
| 486 | } |
| 487 | --pointer_count; |
| 488 | } |
| 489 | |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 490 | m_memory_options.m_byte_size = (clang_ast_type.GetClangTypeBitWidth () + 7) / 8; |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 491 | |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 492 | if (m_memory_options.m_byte_size == 0) |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 493 | { |
| 494 | result.AppendErrorWithFormat ("unable to get the byte size of the type '%s'\n", |
| 495 | view_as_type_cstr); |
| 496 | result.SetStatus(eReturnStatusFailed); |
| 497 | return false; |
| 498 | } |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 499 | |
| 500 | if (!m_memory_options.m_count.OptionWasSet()) |
| 501 | m_memory_options.m_count = 1; |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 502 | } |
| 503 | else |
| 504 | { |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 505 | error = m_memory_options.FinalizeSettings (exe_ctx.target, m_format_options); |
| 506 | } |
| 507 | |
| 508 | // Look for invalid combinations of settings |
| 509 | if (error.Fail()) |
| 510 | { |
| 511 | result.AppendErrorWithFormat("%s", error.AsCString()); |
| 512 | result.SetStatus(eReturnStatusFailed); |
| 513 | return false; |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 514 | } |
| 515 | |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 516 | size_t item_count = m_memory_options.m_count.GetCurrentValue(); |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 517 | const size_t item_byte_size = m_memory_options.m_byte_size; |
| 518 | const size_t num_per_line = m_memory_options.m_num_per_line.GetCurrentValue(); |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 519 | |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 520 | size_t total_byte_size = item_count * item_byte_size; |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 521 | if (total_byte_size == 0) |
| 522 | total_byte_size = 32; |
| 523 | |
| 524 | lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0); |
| 525 | |
| 526 | if (addr == LLDB_INVALID_ADDRESS) |
| 527 | { |
| 528 | result.AppendErrorWithFormat("invalid start address string '%s'.\n", command.GetArgumentAtIndex(0)); |
| 529 | result.SetStatus(eReturnStatusFailed); |
| 530 | return false; |
| 531 | } |
| 532 | |
| 533 | if (argc == 2) |
| 534 | { |
| 535 | lldb::addr_t end_addr = Args::StringToUInt64(command.GetArgumentAtIndex(1), LLDB_INVALID_ADDRESS, 0); |
| 536 | if (end_addr == LLDB_INVALID_ADDRESS) |
| 537 | { |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 538 | result.AppendErrorWithFormat("invalid end address string '%s'.\n", command.GetArgumentAtIndex(1)); |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 539 | result.SetStatus(eReturnStatusFailed); |
| 540 | return false; |
| 541 | } |
| 542 | else if (end_addr <= addr) |
| 543 | { |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 544 | result.AppendErrorWithFormat("end address (0x%llx) must be greater that the start address (0x%llx).\n", end_addr, addr); |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 545 | result.SetStatus(eReturnStatusFailed); |
| 546 | return false; |
| 547 | } |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 548 | else if (m_memory_options.m_count.OptionWasSet()) |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 549 | { |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 550 | result.AppendErrorWithFormat("specify either the end address (0x%llx) or the count (--count %u), not both.\n", end_addr, item_count); |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 551 | result.SetStatus(eReturnStatusFailed); |
| 552 | return false; |
| 553 | } |
| 554 | |
| 555 | total_byte_size = end_addr - addr; |
| 556 | item_count = total_byte_size / item_byte_size; |
| 557 | } |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 558 | |
| 559 | DataBufferSP data_sp; |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 560 | size_t bytes_read = 0; |
| 561 | if (!clang_ast_type.GetOpaqueQualType()) |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 562 | { |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 563 | data_sp.reset (new DataBufferHeap (total_byte_size, '\0')); |
| 564 | bytes_read = exe_ctx.process->ReadMemory(addr, data_sp->GetBytes (), data_sp->GetByteSize(), error); |
| 565 | if (bytes_read == 0) |
| 566 | { |
| 567 | result.AppendWarningWithFormat("Read from 0x%llx failed.\n", addr); |
| 568 | result.AppendError(error.AsCString()); |
| 569 | result.SetStatus(eReturnStatusFailed); |
| 570 | return false; |
| 571 | } |
| 572 | |
| 573 | if (bytes_read < total_byte_size) |
| 574 | result.AppendWarningWithFormat("Not all bytes (%u/%u) were able to be read from 0x%llx.\n", bytes_read, total_byte_size, addr); |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 575 | } |
| 576 | |
Greg Clayton | e9f5fbd | 2010-10-10 20:52:20 +0000 | [diff] [blame] | 577 | StreamFile outfile_stream; |
| 578 | Stream *output_stream = NULL; |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 579 | const FileSpec &outfile_spec = m_outfile_options.GetFile().GetCurrentValue(); |
| 580 | if (outfile_spec) |
Greg Clayton | e9f5fbd | 2010-10-10 20:52:20 +0000 | [diff] [blame] | 581 | { |
| 582 | char path[PATH_MAX]; |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 583 | outfile_spec.GetPath (path, sizeof(path)); |
| 584 | |
| 585 | uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate; |
| 586 | const bool append = m_outfile_options.GetAppend().GetCurrentValue(); |
| 587 | if (append) |
| 588 | open_options |= File::eOpenOptionAppend; |
| 589 | |
| 590 | if (outfile_stream.GetFile ().Open (path, open_options).Success()) |
Greg Clayton | e9f5fbd | 2010-10-10 20:52:20 +0000 | [diff] [blame] | 591 | { |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 592 | if (m_memory_options.m_output_as_binary) |
Greg Clayton | e9f5fbd | 2010-10-10 20:52:20 +0000 | [diff] [blame] | 593 | { |
| 594 | int bytes_written = outfile_stream.Write (data_sp->GetBytes(), bytes_read); |
| 595 | if (bytes_written > 0) |
| 596 | { |
| 597 | result.GetOutputStream().Printf ("%i bytes %s to '%s'\n", |
| 598 | bytes_written, |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 599 | append ? "appended" : "written", |
Greg Clayton | e9f5fbd | 2010-10-10 20:52:20 +0000 | [diff] [blame] | 600 | path); |
| 601 | return true; |
| 602 | } |
| 603 | else |
| 604 | { |
| 605 | result.AppendErrorWithFormat("Failed to write %zu bytes to '%s'.\n", bytes_read, path); |
| 606 | result.SetStatus(eReturnStatusFailed); |
| 607 | return false; |
| 608 | } |
| 609 | } |
| 610 | else |
| 611 | { |
| 612 | // We are going to write ASCII to the file just point the |
| 613 | // output_stream to our outfile_stream... |
| 614 | output_stream = &outfile_stream; |
| 615 | } |
| 616 | } |
| 617 | else |
| 618 | { |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 619 | result.AppendErrorWithFormat("Failed to open file '%s' for %s.\n", path, append ? "append" : "write"); |
Greg Clayton | e9f5fbd | 2010-10-10 20:52:20 +0000 | [diff] [blame] | 620 | result.SetStatus(eReturnStatusFailed); |
| 621 | return false; |
| 622 | } |
| 623 | } |
| 624 | else |
| 625 | { |
| 626 | output_stream = &result.GetOutputStream(); |
| 627 | } |
| 628 | |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 629 | |
| 630 | if (clang_ast_type.GetOpaqueQualType()) |
| 631 | { |
| 632 | for (uint32_t i = 0; i<item_count; ++i) |
| 633 | { |
| 634 | addr_t item_addr = addr + (i * item_byte_size); |
| 635 | Address address (NULL, item_addr); |
| 636 | StreamString name_strm; |
| 637 | name_strm.Printf ("0x%llx", item_addr); |
| 638 | ValueObjectSP valobj_sp (ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(), |
| 639 | name_strm.GetString().c_str(), |
| 640 | address, |
| 641 | clang_ast_type)); |
| 642 | if (valobj_sp) |
| 643 | { |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 644 | if (format != eFormatDefault) |
| 645 | valobj_sp->SetFormat (format); |
| 646 | |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 647 | bool scope_already_checked = true; |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 648 | |
| 649 | ValueObject::DumpValueObject (*output_stream, |
| 650 | valobj_sp.get(), |
| 651 | NULL, |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 652 | m_varobj_options.ptr_depth, |
| 653 | 0, |
| 654 | m_varobj_options.max_depth, |
| 655 | m_varobj_options.show_types, |
| 656 | m_varobj_options.show_location, |
| 657 | m_varobj_options.use_objc, |
Jim Ingham | 10de7d1 | 2011-05-04 03:43:18 +0000 | [diff] [blame] | 658 | m_varobj_options.use_dynamic, |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 659 | scope_already_checked, |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 660 | m_varobj_options.flat_output); |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 661 | } |
| 662 | else |
| 663 | { |
| 664 | result.AppendErrorWithFormat ("failed to create a value object for: (%s) %s\n", |
| 665 | view_as_type_cstr, |
| 666 | name_strm.GetString().c_str()); |
| 667 | result.SetStatus(eReturnStatusFailed); |
| 668 | return false; |
| 669 | } |
| 670 | } |
| 671 | return true; |
| 672 | } |
| 673 | |
| 674 | result.SetStatus(eReturnStatusSuccessFinishResult); |
| 675 | DataExtractor data (data_sp, |
| 676 | exe_ctx.target->GetArchitecture().GetByteOrder(), |
| 677 | exe_ctx.target->GetArchitecture().GetAddressByteSize()); |
| 678 | |
| 679 | |
Greg Clayton | e9f5fbd | 2010-10-10 20:52:20 +0000 | [diff] [blame] | 680 | assert (output_stream); |
| 681 | data.Dump (output_stream, |
| 682 | 0, |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 683 | m_format_options.GetFormat(), |
Greg Clayton | e9f5fbd | 2010-10-10 20:52:20 +0000 | [diff] [blame] | 684 | item_byte_size, |
| 685 | item_count, |
| 686 | num_per_line, |
| 687 | addr, |
| 688 | 0, |
| 689 | 0); |
| 690 | output_stream->EOL(); |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 691 | return true; |
| 692 | } |
| 693 | |
| 694 | protected: |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 695 | // CommandOptions m_options; |
| 696 | OptionGroupOptions m_option_group; |
| 697 | OptionGroupFormat m_format_options; |
| 698 | OptionGroupReadMemory m_memory_options; |
| 699 | OptionGroupOutputFile m_outfile_options; |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 700 | OptionGroupValueObjectDisplay m_varobj_options; |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 701 | |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 702 | }; |
| 703 | |
Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 704 | //OptionDefinition |
| 705 | //CommandObjectMemoryRead::CommandOptions::g_option_table[] = |
| 706 | //{ |
| 707 | //{ LLDB_OPT_SET_1, false, "format" ,'f', required_argument, NULL, 0, eArgTypeFormat ,"The format that will be used to display the memory. Defaults to bytes with ASCII (--format=Y)."}, |
| 708 | //{ LLDB_OPT_SET_1, false, "size" ,'s', required_argument, NULL, 0, eArgTypeByteSize ,"The size in bytes to use when displaying with the selected format."}, |
| 709 | //{ LLDB_OPT_SET_1, false, "num-per-line" ,'l', required_argument, NULL, 0, eArgTypeNumberPerLine ,"The number of items per line to display."}, |
| 710 | //{ LLDB_OPT_SET_1| |
| 711 | // LLDB_OPT_SET_2| |
| 712 | // LLDB_OPT_SET_3, false, "count" ,'c', required_argument, NULL, 0, eArgTypeCount ,"The number of total items to display."}, |
| 713 | //{ LLDB_OPT_SET_1| |
| 714 | // LLDB_OPT_SET_2| |
| 715 | // LLDB_OPT_SET_3, false, "outfile" ,'o', required_argument, NULL, 0, eArgTypeFilename ,"Dump memory read results into a file."}, |
| 716 | //{ LLDB_OPT_SET_1| |
| 717 | // LLDB_OPT_SET_2| |
| 718 | // LLDB_OPT_SET_3, false, "append" ,'a', no_argument , NULL, 0, eArgTypeNone ,"Append memory read results to 'outfile'."}, |
| 719 | //{ LLDB_OPT_SET_2, false, "binary" ,'b', no_argument , NULL, 0, eArgTypeNone ,"If true, memory will be saved as binary. If false, the memory is saved save as an ASCII dump that uses the format, size, count and number per line settings."}, |
| 720 | //{ LLDB_OPT_SET_3, true , "view-as" ,'t', required_argument, NULL, 0, eArgTypeNone ,"The name of a type to view memory as."}, |
| 721 | //{ 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone , NULL } |
| 722 | //}; |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 723 | |
| 724 | //---------------------------------------------------------------------- |
| 725 | // Write memory to the inferior process |
| 726 | //---------------------------------------------------------------------- |
| 727 | class CommandObjectMemoryWrite : public CommandObject |
| 728 | { |
| 729 | public: |
| 730 | |
| 731 | class CommandOptions : public Options |
| 732 | { |
| 733 | public: |
Greg Clayton | f15996e | 2011-04-07 22:46:35 +0000 | [diff] [blame] | 734 | CommandOptions (CommandInterpreter &interpreter) : |
| 735 | Options(interpreter) |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 736 | { |
Greg Clayton | 143fcc3 | 2011-04-13 00:18:08 +0000 | [diff] [blame] | 737 | OptionParsingStarting(); |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 738 | } |
| 739 | |
| 740 | virtual |
| 741 | ~CommandOptions () |
| 742 | { |
| 743 | } |
| 744 | |
| 745 | virtual Error |
Greg Clayton | 143fcc3 | 2011-04-13 00:18:08 +0000 | [diff] [blame] | 746 | SetOptionValue (uint32_t option_idx, const char *option_arg) |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 747 | { |
| 748 | Error error; |
| 749 | char short_option = (char) m_getopt_table[option_idx].val; |
| 750 | switch (short_option) |
| 751 | { |
| 752 | case 'f': |
Greg Clayton | 56bbdaf | 2011-04-28 20:55:26 +0000 | [diff] [blame] | 753 | error = Args::StringToFormat (option_arg, m_format, &m_byte_size); |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 754 | break; |
| 755 | |
| 756 | case 's': |
| 757 | m_byte_size = Args::StringToUInt32 (option_arg, 0); |
| 758 | if (m_byte_size == 0) |
| 759 | error.SetErrorStringWithFormat("Invalid value for --size option '%s'. Must be positive integer value.\n", option_arg); |
| 760 | break; |
| 761 | |
Greg Clayton | e9f5fbd | 2010-10-10 20:52:20 +0000 | [diff] [blame] | 762 | case 'i': |
Greg Clayton | 537a7a8 | 2010-10-20 20:54:39 +0000 | [diff] [blame] | 763 | m_infile.SetFile (option_arg, true); |
Greg Clayton | e9f5fbd | 2010-10-10 20:52:20 +0000 | [diff] [blame] | 764 | if (!m_infile.Exists()) |
| 765 | { |
| 766 | m_infile.Clear(); |
| 767 | error.SetErrorStringWithFormat("Input file does not exist: '%s'\n", option_arg); |
| 768 | } |
| 769 | break; |
| 770 | |
| 771 | case 'o': |
| 772 | { |
| 773 | bool success; |
| 774 | m_infile_offset = Args::StringToUInt64(option_arg, 0, 0, &success); |
| 775 | if (!success) |
| 776 | { |
| 777 | error.SetErrorStringWithFormat("Invalid offset string '%s'\n", option_arg); |
| 778 | } |
| 779 | } |
| 780 | break; |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 781 | |
| 782 | default: |
| 783 | error.SetErrorStringWithFormat("Unrecognized short option '%c'\n", short_option); |
| 784 | break; |
| 785 | } |
| 786 | return error; |
| 787 | } |
| 788 | |
| 789 | void |
Greg Clayton | 143fcc3 | 2011-04-13 00:18:08 +0000 | [diff] [blame] | 790 | OptionParsingStarting () |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 791 | { |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 792 | m_format = eFormatBytes; |
| 793 | m_byte_size = 1; |
Greg Clayton | e9f5fbd | 2010-10-10 20:52:20 +0000 | [diff] [blame] | 794 | m_infile.Clear(); |
| 795 | m_infile_offset = 0; |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 796 | } |
| 797 | |
Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 798 | const OptionDefinition* |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 799 | GetDefinitions () |
| 800 | { |
| 801 | return g_option_table; |
| 802 | } |
| 803 | |
| 804 | // Options table: Required for subclasses of Options. |
| 805 | |
Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 806 | static OptionDefinition g_option_table[]; |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 807 | |
| 808 | // Instance variables to hold the values for command options. |
| 809 | lldb::Format m_format; |
| 810 | uint32_t m_byte_size; |
Greg Clayton | e9f5fbd | 2010-10-10 20:52:20 +0000 | [diff] [blame] | 811 | FileSpec m_infile; |
| 812 | off_t m_infile_offset; |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 813 | }; |
| 814 | |
Greg Clayton | 238c0a1 | 2010-09-18 01:14:36 +0000 | [diff] [blame] | 815 | CommandObjectMemoryWrite (CommandInterpreter &interpreter) : |
| 816 | CommandObject (interpreter, |
| 817 | "memory write", |
Caroline Tice | abb507a | 2010-09-08 21:06:11 +0000 | [diff] [blame] | 818 | "Write to the memory of the process being debugged.", |
Caroline Tice | 43b014a | 2010-10-04 22:28:36 +0000 | [diff] [blame] | 819 | //"memory write [<cmd-options>] <addr> [value1 value2 ...]", |
| 820 | NULL, |
Greg Clayton | f15996e | 2011-04-07 22:46:35 +0000 | [diff] [blame] | 821 | eFlagProcessMustBeLaunched), |
| 822 | m_options (interpreter) |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 823 | { |
Caroline Tice | 43b014a | 2010-10-04 22:28:36 +0000 | [diff] [blame] | 824 | CommandArgumentEntry arg1; |
| 825 | CommandArgumentEntry arg2; |
| 826 | CommandArgumentData addr_arg; |
| 827 | CommandArgumentData value_arg; |
| 828 | |
| 829 | // Define the first (and only) variant of this arg. |
| 830 | addr_arg.arg_type = eArgTypeAddress; |
| 831 | addr_arg.arg_repetition = eArgRepeatPlain; |
| 832 | |
| 833 | // There is only one variant this argument could be; put it into the argument entry. |
| 834 | arg1.push_back (addr_arg); |
| 835 | |
| 836 | // Define the first (and only) variant of this arg. |
| 837 | value_arg.arg_type = eArgTypeValue; |
| 838 | value_arg.arg_repetition = eArgRepeatPlus; |
| 839 | |
| 840 | // There is only one variant this argument could be; put it into the argument entry. |
| 841 | arg2.push_back (value_arg); |
| 842 | |
| 843 | // Push the data for the first argument into the m_arguments vector. |
| 844 | m_arguments.push_back (arg1); |
| 845 | m_arguments.push_back (arg2); |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 846 | } |
| 847 | |
| 848 | virtual |
| 849 | ~CommandObjectMemoryWrite () |
| 850 | { |
| 851 | } |
| 852 | |
| 853 | Options * |
| 854 | GetOptions () |
| 855 | { |
| 856 | return &m_options; |
| 857 | } |
| 858 | |
| 859 | bool |
| 860 | UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size) |
| 861 | { |
| 862 | if (total_byte_size > 8) |
| 863 | return false; |
| 864 | |
| 865 | if (total_byte_size == 8) |
| 866 | return true; |
| 867 | |
| 868 | const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1; |
| 869 | return uval64 <= max; |
| 870 | } |
| 871 | |
| 872 | bool |
| 873 | SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size) |
| 874 | { |
| 875 | if (total_byte_size > 8) |
| 876 | return false; |
| 877 | |
| 878 | if (total_byte_size == 8) |
| 879 | return true; |
| 880 | |
| 881 | const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1; |
| 882 | const int64_t min = ~(max); |
| 883 | return min <= sval64 && sval64 <= max; |
| 884 | } |
| 885 | |
| 886 | virtual bool |
Greg Clayton | 238c0a1 | 2010-09-18 01:14:36 +0000 | [diff] [blame] | 887 | Execute (Args& command, |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 888 | CommandReturnObject &result) |
| 889 | { |
Greg Clayton | b72d0f0 | 2011-04-12 05:54:46 +0000 | [diff] [blame] | 890 | Process *process = m_interpreter.GetExecutionContext().process; |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 891 | if (process == NULL) |
| 892 | { |
| 893 | result.AppendError("need a process to read memory"); |
| 894 | result.SetStatus(eReturnStatusFailed); |
| 895 | return false; |
| 896 | } |
| 897 | |
| 898 | const size_t argc = command.GetArgumentCount(); |
| 899 | |
Greg Clayton | e9f5fbd | 2010-10-10 20:52:20 +0000 | [diff] [blame] | 900 | if (m_options.m_infile) |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 901 | { |
Greg Clayton | e9f5fbd | 2010-10-10 20:52:20 +0000 | [diff] [blame] | 902 | if (argc < 1) |
| 903 | { |
| 904 | result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str()); |
| 905 | result.SetStatus(eReturnStatusFailed); |
| 906 | return false; |
| 907 | } |
| 908 | } |
| 909 | else if (argc < 2) |
| 910 | { |
| 911 | result.AppendErrorWithFormat ("%s takes a destination address and at least one value.\n", m_cmd_name.c_str()); |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 912 | result.SetStatus(eReturnStatusFailed); |
| 913 | return false; |
| 914 | } |
| 915 | |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 916 | StreamString buffer (Stream::eBinary, |
Greg Clayton | 395fc33 | 2011-02-15 21:59:32 +0000 | [diff] [blame] | 917 | process->GetTarget().GetArchitecture().GetAddressByteSize(), |
| 918 | process->GetTarget().GetArchitecture().GetByteOrder()); |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 919 | |
Greg Clayton | 54e7afa | 2010-07-09 20:39:50 +0000 | [diff] [blame] | 920 | size_t item_byte_size = m_options.m_byte_size; |
Greg Clayton | 54e7afa | 2010-07-09 20:39:50 +0000 | [diff] [blame] | 921 | |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 922 | lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0); |
| 923 | |
| 924 | if (addr == LLDB_INVALID_ADDRESS) |
| 925 | { |
| 926 | result.AppendErrorWithFormat("Invalid address string '%s'.\n", command.GetArgumentAtIndex(0)); |
| 927 | result.SetStatus(eReturnStatusFailed); |
| 928 | return false; |
| 929 | } |
Greg Clayton | e9f5fbd | 2010-10-10 20:52:20 +0000 | [diff] [blame] | 930 | |
| 931 | if (m_options.m_infile) |
| 932 | { |
| 933 | size_t length = SIZE_MAX; |
| 934 | if (m_options.m_byte_size > 0) |
| 935 | length = m_options.m_byte_size; |
| 936 | lldb::DataBufferSP data_sp (m_options.m_infile.ReadFileContents (m_options.m_infile_offset, length)); |
| 937 | if (data_sp) |
| 938 | { |
| 939 | length = data_sp->GetByteSize(); |
| 940 | if (length > 0) |
| 941 | { |
| 942 | Error error; |
| 943 | size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error); |
| 944 | |
| 945 | if (bytes_written == length) |
| 946 | { |
| 947 | // All bytes written |
| 948 | result.GetOutputStream().Printf("%zu bytes were written to 0x%llx\n", bytes_written, addr); |
| 949 | result.SetStatus(eReturnStatusSuccessFinishResult); |
| 950 | } |
| 951 | else if (bytes_written > 0) |
| 952 | { |
| 953 | // Some byte written |
| 954 | result.GetOutputStream().Printf("%zu bytes of %zu requested were written to 0x%llx\n", bytes_written, length, addr); |
| 955 | result.SetStatus(eReturnStatusSuccessFinishResult); |
| 956 | } |
| 957 | else |
| 958 | { |
| 959 | result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); |
| 960 | result.SetStatus(eReturnStatusFailed); |
| 961 | } |
| 962 | } |
| 963 | } |
| 964 | else |
| 965 | { |
| 966 | result.AppendErrorWithFormat ("Unable to read contents of file.\n"); |
| 967 | result.SetStatus(eReturnStatusFailed); |
| 968 | } |
| 969 | return result.Succeeded(); |
| 970 | } |
| 971 | else if (m_options.m_byte_size == 0) |
| 972 | { |
| 973 | if (m_options.m_format == eFormatPointer) |
| 974 | item_byte_size = buffer.GetAddressByteSize(); |
| 975 | else |
| 976 | item_byte_size = 1; |
| 977 | } |
| 978 | |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 979 | command.Shift(); // shift off the address argument |
| 980 | uint64_t uval64; |
| 981 | int64_t sval64; |
| 982 | bool success = false; |
| 983 | const uint32_t num_value_args = command.GetArgumentCount(); |
| 984 | uint32_t i; |
| 985 | for (i=0; i<num_value_args; ++i) |
| 986 | { |
| 987 | const char *value_str = command.GetArgumentAtIndex(i); |
| 988 | |
| 989 | switch (m_options.m_format) |
| 990 | { |
| 991 | case eFormatFloat: // TODO: add support for floats soon |
| 992 | case eFormatCharPrintable: |
| 993 | case eFormatBytesWithASCII: |
| 994 | case eFormatComplex: |
| 995 | case eFormatEnum: |
| 996 | case eFormatUnicode16: |
| 997 | case eFormatUnicode32: |
| 998 | case eFormatVectorOfChar: |
| 999 | case eFormatVectorOfSInt8: |
| 1000 | case eFormatVectorOfUInt8: |
| 1001 | case eFormatVectorOfSInt16: |
| 1002 | case eFormatVectorOfUInt16: |
| 1003 | case eFormatVectorOfSInt32: |
| 1004 | case eFormatVectorOfUInt32: |
| 1005 | case eFormatVectorOfSInt64: |
| 1006 | case eFormatVectorOfUInt64: |
| 1007 | case eFormatVectorOfFloat32: |
| 1008 | case eFormatVectorOfFloat64: |
| 1009 | case eFormatVectorOfUInt128: |
Greg Clayton | 4fdf760 | 2011-03-20 04:57:14 +0000 | [diff] [blame] | 1010 | case eFormatOSType: |
| 1011 | case eFormatComplexInteger: |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 1012 | result.AppendError("unsupported format for writing memory"); |
| 1013 | result.SetStatus(eReturnStatusFailed); |
| 1014 | return false; |
| 1015 | |
| 1016 | case eFormatDefault: |
| 1017 | case eFormatBytes: |
| 1018 | case eFormatHex: |
Greg Clayton | 54e7afa | 2010-07-09 20:39:50 +0000 | [diff] [blame] | 1019 | case eFormatPointer: |
| 1020 | |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 1021 | // Decode hex bytes |
| 1022 | uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success); |
| 1023 | if (!success) |
| 1024 | { |
| 1025 | result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str); |
| 1026 | result.SetStatus(eReturnStatusFailed); |
| 1027 | return false; |
| 1028 | } |
| 1029 | else if (!UIntValueIsValidForSize (uval64, item_byte_size)) |
| 1030 | { |
| 1031 | result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); |
| 1032 | result.SetStatus(eReturnStatusFailed); |
| 1033 | return false; |
| 1034 | } |
| 1035 | buffer.PutMaxHex64 (uval64, item_byte_size); |
| 1036 | break; |
| 1037 | |
| 1038 | case eFormatBoolean: |
| 1039 | uval64 = Args::StringToBoolean(value_str, false, &success); |
| 1040 | if (!success) |
| 1041 | { |
| 1042 | result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str); |
| 1043 | result.SetStatus(eReturnStatusFailed); |
| 1044 | return false; |
| 1045 | } |
| 1046 | buffer.PutMaxHex64 (uval64, item_byte_size); |
| 1047 | break; |
| 1048 | |
| 1049 | case eFormatBinary: |
| 1050 | uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success); |
| 1051 | if (!success) |
| 1052 | { |
| 1053 | result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str); |
| 1054 | result.SetStatus(eReturnStatusFailed); |
| 1055 | return false; |
| 1056 | } |
| 1057 | else if (!UIntValueIsValidForSize (uval64, item_byte_size)) |
| 1058 | { |
| 1059 | result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); |
| 1060 | result.SetStatus(eReturnStatusFailed); |
| 1061 | return false; |
| 1062 | } |
| 1063 | buffer.PutMaxHex64 (uval64, item_byte_size); |
| 1064 | break; |
| 1065 | |
Greg Clayton | 307fa07 | 2011-06-17 23:50:44 +0000 | [diff] [blame^] | 1066 | case eFormatCharArray: |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 1067 | case eFormatChar: |
| 1068 | case eFormatCString: |
| 1069 | if (value_str[0]) |
| 1070 | { |
| 1071 | size_t len = strlen (value_str); |
| 1072 | // Include the NULL for C strings... |
| 1073 | if (m_options.m_format == eFormatCString) |
| 1074 | ++len; |
| 1075 | Error error; |
| 1076 | if (process->WriteMemory (addr, value_str, len, error) == len) |
| 1077 | { |
| 1078 | addr += len; |
| 1079 | } |
| 1080 | else |
| 1081 | { |
| 1082 | result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); |
| 1083 | result.SetStatus(eReturnStatusFailed); |
| 1084 | return false; |
| 1085 | } |
| 1086 | } |
| 1087 | break; |
| 1088 | |
| 1089 | case eFormatDecimal: |
| 1090 | sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success); |
| 1091 | if (!success) |
| 1092 | { |
| 1093 | result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str); |
| 1094 | result.SetStatus(eReturnStatusFailed); |
| 1095 | return false; |
| 1096 | } |
| 1097 | else if (!SIntValueIsValidForSize (sval64, item_byte_size)) |
| 1098 | { |
| 1099 | result.AppendErrorWithFormat ("Value %lli is too large or small to fit in a %u byte signed integer value.\n", sval64, item_byte_size); |
| 1100 | result.SetStatus(eReturnStatusFailed); |
| 1101 | return false; |
| 1102 | } |
| 1103 | buffer.PutMaxHex64 (sval64, item_byte_size); |
| 1104 | break; |
| 1105 | |
| 1106 | case eFormatUnsigned: |
| 1107 | uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success); |
| 1108 | if (!success) |
| 1109 | { |
| 1110 | result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str); |
| 1111 | result.SetStatus(eReturnStatusFailed); |
| 1112 | return false; |
| 1113 | } |
| 1114 | else if (!UIntValueIsValidForSize (uval64, item_byte_size)) |
| 1115 | { |
| 1116 | result.AppendErrorWithFormat ("Value %llu is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); |
| 1117 | result.SetStatus(eReturnStatusFailed); |
| 1118 | return false; |
| 1119 | } |
| 1120 | buffer.PutMaxHex64 (uval64, item_byte_size); |
| 1121 | break; |
| 1122 | |
| 1123 | case eFormatOctal: |
| 1124 | uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success); |
| 1125 | if (!success) |
| 1126 | { |
| 1127 | result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str); |
| 1128 | result.SetStatus(eReturnStatusFailed); |
| 1129 | return false; |
| 1130 | } |
| 1131 | else if (!UIntValueIsValidForSize (uval64, item_byte_size)) |
| 1132 | { |
| 1133 | result.AppendErrorWithFormat ("Value %llo is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); |
| 1134 | result.SetStatus(eReturnStatusFailed); |
| 1135 | return false; |
| 1136 | } |
| 1137 | buffer.PutMaxHex64 (uval64, item_byte_size); |
| 1138 | break; |
| 1139 | } |
| 1140 | } |
| 1141 | |
| 1142 | if (!buffer.GetString().empty()) |
| 1143 | { |
| 1144 | Error error; |
Greg Clayton | 53d68e7 | 2010-07-20 22:52:08 +0000 | [diff] [blame] | 1145 | if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size()) |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 1146 | return true; |
| 1147 | else |
| 1148 | { |
| 1149 | result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); |
| 1150 | result.SetStatus(eReturnStatusFailed); |
| 1151 | return false; |
| 1152 | } |
| 1153 | } |
| 1154 | return true; |
| 1155 | } |
| 1156 | |
| 1157 | protected: |
| 1158 | CommandOptions m_options; |
| 1159 | }; |
| 1160 | |
Greg Clayton | e9f5fbd | 2010-10-10 20:52:20 +0000 | [diff] [blame] | 1161 | #define SET1 LLDB_OPT_SET_1 |
| 1162 | #define SET2 LLDB_OPT_SET_2 |
| 1163 | |
Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 1164 | OptionDefinition |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 1165 | CommandObjectMemoryWrite::CommandOptions::g_option_table[] = |
| 1166 | { |
Greg Clayton | e9f5fbd | 2010-10-10 20:52:20 +0000 | [diff] [blame] | 1167 | { SET1 , false, "format", 'f', required_argument, NULL, 0, eArgTypeFormat, "The format value types that will be decoded and written to memory."}, |
| 1168 | { SET1 | SET2, false, "size", 's', required_argument, NULL, 0, eArgTypeByteSize, "The size in bytes of the values to write to memory."}, |
| 1169 | { SET2, true, "infile", 'i', required_argument, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."}, |
| 1170 | { SET2, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset, "Start writng bytes from an offset within the input file."}, |
| 1171 | { 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone, NULL } |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 1172 | }; |
| 1173 | |
Greg Clayton | e9f5fbd | 2010-10-10 20:52:20 +0000 | [diff] [blame] | 1174 | #undef SET1 |
| 1175 | #undef SET2 |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 1176 | |
| 1177 | //------------------------------------------------------------------------- |
| 1178 | // CommandObjectMemory |
| 1179 | //------------------------------------------------------------------------- |
| 1180 | |
Greg Clayton | 63094e0 | 2010-06-23 01:19:29 +0000 | [diff] [blame] | 1181 | CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) : |
Greg Clayton | 238c0a1 | 2010-09-18 01:14:36 +0000 | [diff] [blame] | 1182 | CommandObjectMultiword (interpreter, |
| 1183 | "memory", |
Caroline Tice | c1ad82e | 2010-09-07 22:38:08 +0000 | [diff] [blame] | 1184 | "A set of commands for operating on memory.", |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 1185 | "memory <subcommand> [<subcommand-options>]") |
| 1186 | { |
Greg Clayton | 238c0a1 | 2010-09-18 01:14:36 +0000 | [diff] [blame] | 1187 | LoadSubCommand ("read", CommandObjectSP (new CommandObjectMemoryRead (interpreter))); |
| 1188 | LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter))); |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 1189 | } |
| 1190 | |
| 1191 | CommandObjectMemory::~CommandObjectMemory () |
| 1192 | { |
| 1193 | } |