| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/developer/debug/zxdb/console/commands/verb_stack.h" |
| |
| #include "src/developer/debug/zxdb/client/frame.h" |
| #include "src/developer/debug/zxdb/client/target.h" |
| #include "src/developer/debug/zxdb/console/analyze_memory.h" |
| #include "src/developer/debug/zxdb/console/async_output_buffer.h" |
| #include "src/developer/debug/zxdb/console/command.h" |
| #include "src/developer/debug/zxdb/console/command_utils.h" |
| #include "src/developer/debug/zxdb/console/commands/verb_mem_analyze.h" |
| #include "src/developer/debug/zxdb/console/console.h" |
| #include "src/developer/debug/zxdb/console/output_buffer.h" |
| #include "src/developer/debug/zxdb/console/verbs.h" |
| #include "src/lib/fxl/strings/string_printf.h" |
| |
| namespace zxdb { |
| |
| namespace { |
| |
| // Needs to not collide with the kMemAnalyze*Switches. |
| constexpr int kOffsetSwitch = 100; |
| |
| const char kStackShortHelp[] = "stack / st: Analyze the stack."; |
| const char kStackHelp[] = |
| R"(stack [ --offset=<offset> ] [ --num=<lines> ] [ --size=<bytes> ] |
| [ <address-expression> ] |
| |
| Alias: "st" |
| |
| Prints a stack analysis. This is a special case of "mem-analyze" that |
| defaults to showing the memory address starting at the current frame's stack |
| pointer, and annotates the values with the current thread's registers and |
| stack frames. |
| |
| An explicit address can optionally be provided to begin dumping to dump at |
| somewhere other than the current frame's stack pointer (this address can be |
| any expression that evaluates to an address, see "help expressions"), or you |
| can provide an --offset from the current stack position. |
| |
| Arguments |
| |
| --num=<lines> | -n <lines> |
| The number of output lines. Each line is the size of one pointer, so |
| the amount of memory displayed on a 64-bit system will be 8 × num_lines. |
| Mutually exclusive with --size. |
| |
| --offset=<offset> | -o <offset> |
| Offset from the stack pointer to begin dumping. Mutually exclusive with |
| <address>. |
| |
| --size=<bytes> | -s <bytes> |
| The number of bytes to analyze. This will be rounded up to the nearest |
| pointer boundary. Mutually exclusive with --num. |
| |
| Examples |
| |
| stack |
| thread 2 stack |
| |
| stack --num=128 0x43011a14bfc8 |
| )"; |
| Err RunVerbStack(ConsoleContext* context, const Command& cmd) { |
| Err err = AssertStoppedThreadWithFrameCommand(context, cmd, "stack"); |
| if (err.has_error()) |
| return err; |
| |
| AnalyzeMemoryOptions opts; |
| opts.process = cmd.target()->GetProcess(); |
| opts.thread = cmd.thread(); |
| |
| // Begin address. |
| if (cmd.args().size() == 1) { |
| // Explicitly provided start address. |
| Err err = StringToUint64(cmd.args()[0], &opts.begin_address); |
| if (err.has_error()) |
| return err; |
| } else if (cmd.args().size() > 1) { |
| return Err("Too many args to \"stack\", expecting 0 or 1."); |
| } else { |
| // Use implicit SP from the frame (with optional --offset). |
| opts.begin_address = cmd.frame()->GetStackPointer(); |
| if (cmd.HasSwitch(kOffsetSwitch)) { |
| int offset = 0; |
| Err err = StringToInt(cmd.GetSwitchValue(kOffsetSwitch), &offset); |
| if (err.has_error()) |
| return err; |
| opts.begin_address += offset; |
| } |
| } |
| |
| // Length parameters. |
| std::optional<uint32_t> input_size; |
| err = ReadAnalyzeNumAndSizeSwitches(cmd, &input_size); |
| if (err.has_error()) |
| return err; |
| if (!input_size) |
| opts.bytes_to_read = kDefaultAnalyzeByteSize; |
| else |
| opts.bytes_to_read = *input_size; |
| |
| auto async_output = fxl::MakeRefCounted<AsyncOutputBuffer>(); |
| Console::get()->Output(async_output); |
| |
| AnalyzeMemory(opts, [bytes_to_read = opts.bytes_to_read, async_output]( |
| const Err& err, OutputBuffer output, uint64_t next_addr) { |
| async_output->Append(std::move(output)); |
| if (err.has_error()) { |
| async_output->Append(err); |
| } else { |
| // Help text for continuation. |
| async_output->Append( |
| Syntax::kComment, |
| fxl::StringPrintf("↓ For more lines: stack -n %d 0x%" PRIx64, |
| static_cast<int>(bytes_to_read / sizeof(uint64_t)), next_addr)); |
| } |
| async_output->Complete(); |
| }); |
| return Err(); |
| } |
| |
| } // namespace |
| |
| VerbRecord GetStackVerbRecord() { |
| VerbRecord stack(&RunVerbStack, {"stack", "st"}, kStackShortHelp, kStackHelp, |
| CommandGroup::kQuery); |
| stack.switches.emplace_back(kMemAnalyzeSizeSwitch, true, "size", 's'); |
| stack.switches.emplace_back(kMemAnalyzeNumSwitch, true, "num", 'n'); |
| stack.switches.push_back(SwitchRecord(kOffsetSwitch, true, "offset", 'o')); |
| return stack; |
| } |
| |
| } // namespace zxdb |