| // 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/format_location.h" |
| |
| #include "src/developer/debug/zxdb/client/session.h" |
| #include "src/developer/debug/zxdb/client/setting_schema_definition.h" |
| #include "src/developer/debug/zxdb/client/system.h" |
| #include "src/developer/debug/zxdb/common/string_util.h" |
| #include "src/developer/debug/zxdb/console/string_util.h" |
| #include "src/developer/debug/zxdb/symbols/elf_symbol.h" |
| #include "src/developer/debug/zxdb/symbols/function.h" |
| #include "src/developer/debug/zxdb/symbols/location.h" |
| #include "src/developer/debug/zxdb/symbols/target_symbols.h" |
| #include "src/lib/fxl/strings/string_printf.h" |
| |
| namespace zxdb { |
| |
| FormatLocationOptions::FormatLocationOptions(const Target* target) : FormatLocationOptions() { |
| if (target) { |
| show_file_path = |
| target->session()->system().settings().GetBool(ClientSettings::System::kShowFilePaths); |
| target_symbols = target->GetSymbols(); |
| } |
| } |
| |
| OutputBuffer FormatLocation(const Location& loc, const FormatLocationOptions& opts) { |
| if (!loc.is_valid()) |
| return OutputBuffer("<invalid address>"); |
| if (!loc.has_symbols()) |
| return OutputBuffer(fxl::StringPrintf("0x%" PRIx64, loc.address())); |
| |
| OutputBuffer result; |
| if (opts.always_show_addresses) { |
| result = OutputBuffer(Syntax::kComment, fxl::StringPrintf("0x%" PRIx64 ", ", loc.address())); |
| } |
| |
| bool show_file_line = opts.show_file_line && loc.file_line().is_valid(); |
| |
| const Symbol* symbol = loc.symbol().Get(); |
| if (const Function* func = symbol->AsFunction()) { |
| // Regular function. |
| OutputBuffer func_output = FormatFunctionName(func, opts.func); |
| if (!func_output.empty()) { |
| result.Append(std::move(func_output)); |
| if (show_file_line) { |
| // Separator between function and file/line. |
| result.Append(" " + GetBullet() + " "); |
| } else { |
| // Check if the address is inside a function and show the offset. |
| AddressRange function_range = func->GetFullRange(loc.symbol_context()); |
| if (function_range.InRange(loc.address())) { |
| // Inside a function but no file/line known. Show the offset. |
| uint64_t offset = loc.address() - function_range.begin(); |
| if (offset) |
| result.Append(fxl::StringPrintf(" + 0x%" PRIx64, offset)); |
| if (opts.show_file_line) |
| result.Append(Syntax::kComment, " (no line info)"); |
| } |
| } |
| } |
| } else if (const ElfSymbol* elf_symbol = symbol->AsElfSymbol()) { |
| // ELF symbol. |
| FormatIdentifierOptions opts; |
| opts.show_global_qual = false; |
| opts.bold_last = true; |
| result.Append(FormatIdentifier(symbol->GetIdentifier(), opts)); |
| |
| // The address might not be at the beginning of the symbol. |
| if (uint64_t offset = |
| loc.address() - loc.symbol_context().RelativeToAbsolute(elf_symbol->relative_address())) |
| result.Append(fxl::StringPrintf(" + 0x%" PRIx64, offset)); |
| } else { |
| // All other symbol types. This case must handle all other symbol types, some of which might |
| // not have identifiers. |
| bool printed_name = false; |
| if (!symbol->GetIdentifier().empty()) { |
| FormatIdentifierOptions opts; |
| opts.show_global_qual = false; |
| opts.bold_last = true; |
| result.Append(FormatIdentifier(symbol->GetIdentifier(), opts)); |
| printed_name = true; |
| } else if (!symbol->GetFullName().empty()) { |
| // Fall back on the name. |
| result.Append(symbol->GetFullName()); |
| printed_name = true; |
| } else if (!opts.always_show_addresses) { |
| // Unnamed symbol, use the address (unless it was printed above already). |
| result.Append(to_hex_string(loc.address())); |
| printed_name = true; |
| } |
| |
| // Separator between function and file/line. |
| if (printed_name && show_file_line) |
| result.Append(" " + GetBullet() + " "); |
| } |
| |
| if (show_file_line) { |
| // Showing the file path means not passing the target symbols because the target symbols is |
| // used to shorten the paths. |
| result.Append( |
| FormatFileLine(loc.file_line(), opts.show_file_path ? nullptr : opts.target_symbols)); |
| } |
| return result; |
| } |
| |
| OutputBuffer FormatFile(const std::string& file_name, |
| const TargetSymbols* optional_target_symbols) { |
| if (file_name.empty()) { |
| return OutputBuffer(Syntax::kFileName, "?"); |
| } |
| if (!optional_target_symbols) { |
| // Use full file name. |
| return OutputBuffer(Syntax::kFileName, file_name); |
| } |
| |
| // Try to generate the shortest unique file name. |
| return OutputBuffer(Syntax::kFileName, |
| optional_target_symbols->GetShortestUniqueFileName(file_name)); |
| } |
| |
| OutputBuffer FormatFileLine(const FileLine& file_line, |
| const TargetSymbols* optional_target_symbols) { |
| // File name. |
| OutputBuffer result = FormatFile(file_line.file(), optional_target_symbols); |
| result.Append(Syntax::kComment, ":"); |
| |
| // Line. |
| if (file_line.line() == 0) { |
| result.Append("?"); |
| } else { |
| result.Append(std::to_string(file_line.line())); |
| } |
| |
| return result; |
| } |
| |
| } // namespace zxdb |