blob: 89ffd8f728218f6b89e7cd178f42510f54e409d7 [file] [log] [blame]
// 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.
#ifndef SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_LOCATION_H_
#define SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_LOCATION_H_
#include <stdint.h>
#include "src/developer/debug/zxdb/symbols/file_line.h"
#include "src/developer/debug/zxdb/symbols/lazy_symbol.h"
#include "src/developer/debug/zxdb/symbols/symbol_context.h"
namespace zxdb {
class CodeBlock;
class Function;
// Represents all the symbol information for a code location.
class Location {
public:
// A location can be invalid (has no address), can have an address that we haven't tried to
// symbolize, and a symbolized address. The latter two states allow symbolizing on demand without
// having additional types.
//
// The "symbolized" state doesn't necessarily mean there are symbols, it just means we tried to
// symbolize it.
enum class State {
// There is no address or data for this location.
kInvalid,
// There is an address for this location but we haven't tried to symbolize it.
kAddress,
// There is an address for the location and we tried to symbolize it. This doesn't mean that
// symbolization succeeded, so the symbol() and file/line could still be empty.
kSymbolized,
// The symbol corresponds to a Variable, but its location has not been computed so it will have
// a null address.
//
// Some global variables actually need to be evaluated asynchronously based on the current CPU
// state. For example, TLS values are located relative to the CPU register that indicates the
// TLS base. When resolving a symbolic name, we can encounter these which can't be evaluated in
// the global context of the symbol system.
//
// Currently these aren't handled in most places. But if a caller is in a position to evaluate
// this it can fill out the address from the symbol.
kUnlocatedVariable,
};
Location();
Location(State state, uint64_t address);
// Symbolized location.
Location(uint64_t address, FileLine file_line, int column, const SymbolContext& symbol_context,
LazySymbol symbol = LazySymbol());
// Unlocated variable.
Location(const SymbolContext& symbol_context, LazySymbol symbol);
~Location();
bool is_valid() const { return state_ != State::kInvalid; }
// The different between "symbolized" and "has_symbols" is that the former means we tried to
// symbolize it, and the latter means we actually succeeded to symbolize EITHER the line or the
// function. One or the other could be missing, however.
bool is_symbolized() const { return state_ == State::kSymbolized; }
bool has_symbols() const { return file_line_.is_valid() || symbol_; }
// The absolute address of this location.
uint64_t address() const { return address_; }
const FileLine& file_line() const { return file_line_; }
int column() const { return column_; }
// The symbol associated with this address, if any. In the case of code this will most commonly be
// a Function. It will not be a non-function code block inside the function (code wanting lexical
// blocks can look inside the function's children as needed). It could also be a variable symbol
// corresponding to a global or static variable or an ELF symbol.
//
// When looking up code locations from the symbol system and the address is non-ambiguous,
// this will be the most specific (possibly inline) function covering the address in
// question. For ambiguous inline locations this will either be the most specific inline function
// or the non-inline function (least-specific) according to ResolveOptions.ambiguous_inline (see
// that variable for more on ambiguous inline locations).
//
// A function can have different scopes inside of it. To get the current lexical scope inside the
// function, use GetMostSpecificChild() on it.
//
// This isn't necessarily valid, even if the State == kSymbolized. It could be the symbol table
// indicates file/line info for this address but could lack a function record for it.
const LazySymbol& symbol() const { return symbol_; }
// Symbolized locations will have a valid symbol context for converting addresses.
const SymbolContext& symbol_context() const { return symbol_context_; }
// Offsets the code addresses in this by adding an amount. This is used to convert module-relative
// addresses to global ones by adding the module load address.
void AddAddressOffset(uint64_t offset);
// Returns if this location is the same as the other one, ignoring the symbol() object. Comparing
// symbol objects is dicy because the same symbol can result in a different object depending on
// how it is found or whether it was re-queried.
//
// This function is primarily used for tests, in which case comparing object pointer equality
// might be good enough. For non-tests, one might compare symbols by name.
bool EqualsIgnoringSymbol(const Location& other) const;
// Returns a string version of the State enum for debugging purposes.
static const char* StateToString(State state);
// Returns a description of this Location for debugging purposes.
std::string GetDebugString() const;
private:
State state_ = State::kInvalid;
uint64_t address_ = 0;
FileLine file_line_;
int column_ = 0;
LazySymbol symbol_;
SymbolContext symbol_context_ = SymbolContext::ForRelativeAddresses();
};
} // namespace zxdb
#endif // SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_LOCATION_H_