| // Copyright 2018 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 "garnet/bin/zxdb/console/input_location_parser.h" |
| |
| #include <inttypes.h> |
| |
| #include "garnet/bin/zxdb/client/frame.h" |
| #include "garnet/bin/zxdb/client/process.h" |
| #include "garnet/bin/zxdb/console/command_utils.h" |
| #include "garnet/bin/zxdb/console/string_util.h" |
| #include "garnet/bin/zxdb/symbols/location.h" |
| #include "garnet/bin/zxdb/symbols/process_symbols.h" |
| #include "lib/fxl/strings/string_printf.h" |
| |
| namespace zxdb { |
| |
| Err ParseInputLocation(const Frame* frame, const std::string& input, |
| InputLocation* location) { |
| if (input.empty()) |
| return Err("Passed empty location."); |
| |
| // Check for one colon. Two colons is a C++ member function. |
| size_t colon = input.find(':'); |
| if (colon != std::string::npos && colon < input.size() - 1 && |
| input[colon + 1] != ':') { |
| // <file>:<line> format. |
| std::string file = input.substr(0, colon); |
| |
| uint64_t line = 0; |
| Err err = StringToUint64(input.substr(colon + 1), &line); |
| if (err.has_error()) |
| return err; |
| |
| location->type = InputLocation::Type::kLine; |
| location->line = FileLine(std::move(file), static_cast<int>(line)); |
| return Err(); |
| } |
| |
| // Check for memory addresses. |
| bool is_address = false; |
| size_t address_begin = 0; // Index of address number when is_address. |
| if (input[0] == '*') { |
| // *<address> format |
| is_address = true; |
| address_begin = 1; // Skip "*". |
| } else if (CheckHexPrefix(input)) { |
| // Hex numbers are addresses. |
| is_address = true; |
| address_begin = 0; |
| } |
| if (is_address) { |
| std::string addr_str = input.substr(address_begin); |
| Err err = StringToUint64(addr_str, &location->address); |
| if (err.has_error()) |
| return err; |
| |
| location->type = InputLocation::Type::kAddress; |
| return Err(); |
| } |
| |
| uint64_t line = 0; |
| Err err = StringToUint64(input, &line); |
| if (err.has_error()) { |
| // Not a number, assume symbol. |
| location->type = InputLocation::Type::kSymbol; |
| location->symbol = input; |
| return Err(); |
| } |
| |
| // Just a number, use the file name from the specified frame. |
| if (!frame) { |
| return Err( |
| "There is no current frame to get a file name, you'll have to " |
| "specify an explicit frame or file name."); |
| } |
| const Location& frame_location = frame->GetLocation(); |
| if (frame_location.file_line().file().empty()) { |
| return Err( |
| "The current frame doesn't have a file name to use, you'll " |
| "have to specify a file."); |
| } |
| location->type = InputLocation::Type::kLine; |
| location->line = |
| FileLine(frame_location.file_line().file(), static_cast<int>(line)); |
| return Err(); |
| } |
| |
| Err ResolveInputLocations(const ProcessSymbols* process_symbols, |
| const InputLocation& input_location, bool symbolize, |
| std::vector<Location>* locations) { |
| ResolveOptions options; |
| options.symbolize = symbolize; |
| *locations = process_symbols->ResolveInputLocation(input_location, options); |
| |
| if (locations->empty()) { |
| return Err("Nothing matching this %s was found.", |
| InputLocation::TypeToString(input_location.type)); |
| } |
| return Err(); |
| } |
| |
| Err ResolveInputLocations(const ProcessSymbols* process_symbols, |
| const Frame* optional_frame, const std::string& input, |
| bool symbolize, std::vector<Location>* locations) { |
| InputLocation input_location; |
| Err err = ParseInputLocation(optional_frame, input, &input_location); |
| if (err.has_error()) |
| return err; |
| return ResolveInputLocations(process_symbols, input_location, symbolize, |
| locations); |
| } |
| |
| Err ResolveUniqueInputLocation(const ProcessSymbols* process_symbols, |
| const InputLocation& input_location, |
| bool symbolize, Location* location) { |
| std::vector<Location> locations; |
| Err err = ResolveInputLocations(process_symbols, input_location, symbolize, |
| &locations); |
| if (err.has_error()) |
| return err; |
| |
| FXL_DCHECK(!locations.empty()); // Non-empty on success should be guaranteed. |
| |
| if (locations.size() == 1u) { |
| // Success, got a unique location. |
| *location = locations[0]; |
| return Err(); |
| } |
| |
| // When there is more than one, generate an error that lists the |
| // possibilities for disambiguation. |
| std::string err_str = "This resolves to more than one location. Could be:\n"; |
| constexpr size_t kMaxSuggestions = 10u; |
| |
| if (!symbolize) { |
| // The original call did not request symbolization which will produce very |
| // non-helpful suggestions. We're not concerned about performance in this |
| // error case so re-query to get the full symbols. |
| locations.clear(); |
| ResolveInputLocations(process_symbols, input_location, true, &locations); |
| } |
| |
| for (size_t i = 0; i < locations.size() && i < kMaxSuggestions; i++) { |
| // Always show the full path since we're doing disambiguation and the |
| // problem could have been two files with the same name but different |
| // paths. |
| err_str += fxl::StringPrintf(" %s ", GetBullet().c_str()); |
| if (locations[i].file_line().is_valid()) { |
| err_str += DescribeFileLine(locations[i].file_line(), true); |
| err_str += fxl::StringPrintf(" = 0x%" PRIx64, locations[i].address()); |
| } else { |
| err_str += FormatLocation(locations[i], true, false).AsString(); |
| } |
| err_str += "\n"; |
| } |
| if (locations.size() > kMaxSuggestions) { |
| err_str += fxl::StringPrintf("...%zu more omitted...\n", |
| locations.size() - kMaxSuggestions); |
| } |
| return Err(err_str); |
| } |
| |
| Err ResolveUniqueInputLocation(const ProcessSymbols* process_symbols, |
| const Frame* optional_frame, |
| const std::string& input, bool symbolize, |
| Location* location) { |
| InputLocation input_location; |
| Err err = ParseInputLocation(optional_frame, input, &input_location); |
| if (err.has_error()) |
| return err; |
| return ResolveUniqueInputLocation(process_symbols, input_location, symbolize, |
| location); |
| } |
| |
| } // namespace zxdb |