blob: 3d8f55476d3ca1093c612b4cb7dad5e313d07640 [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.
#pragma once
#include <stdint.h>
#include <functional>
#include <map>
#include <memory>
#include <string>
#include "garnet/bin/zxdb/symbols/location.h"
#include "garnet/bin/zxdb/symbols/resolve_options.h"
#include "garnet/bin/zxdb/symbols/system_symbols.h"
#include "garnet/public/lib/fxl/macros.h"
#include "lib/fxl/macros.h"
#include "lib/fxl/memory/weak_ptr.h"
namespace debug_ipc {
struct Module;
}
namespace zxdb {
struct InputLocation;
class LineDetails;
class LoadedModuleSymbols;
struct ModuleSymbolStatus;
struct ResolveOptions;
class TargetSymbols;
// Main client interface for querying process symbol information. This requires
// a running process and returns real addresses. See also TargetSymbols.
//
// This class is a collection for modules. As such, it's not very useful to
// mock. Instead, mock the ModuleSymbols and add them to this ProcessSymbols
// class (see ProcessSymbolsTestSetup helper class).
class ProcessSymbols {
public:
// A simple observer interface. This allows ProcessImpl to expose these
// in the ProcessObserver observer API. If the API here gets too much more
// complicated, it could be we want a separate public ProcessSymbolsObserver
// class that consumers need to register for explicitly.
//
// See the corresponding functions in ProcessObserver for docs.
class Notifications {
public:
virtual void DidLoadModuleSymbols(LoadedModuleSymbols* module) {}
virtual void WillUnloadModuleSymbols(LoadedModuleSymbols* module) {}
virtual void OnSymbolLoadFailure(const Err& err) {}
};
// The passed-in pointers must outlive this class.
ProcessSymbols(Notifications* notifications, TargetSymbols* target_symbols);
~ProcessSymbols();
fxl::WeakPtr<const ProcessSymbols> GetWeakPtr() const;
TargetSymbols* target_symbols() { return target_symbols_; }
// Replaces all modules with the given list.
void SetModules(const std::vector<debug_ipc::Module>& modules);
// Appends the ModuleSymbols implementation to the current list (unlike
// SetModules which does a replacement). This is typically used to populate
// a ProcessSymbols with one or more MockModuleSymbols for testing purposes.
void InjectModuleForTesting(const std::string& name,
const std::string& build_id,
std::unique_ptr<LoadedModuleSymbols> mod_sym);
// Returns statistics on the currently-loaded modules.
std::vector<ModuleSymbolStatus> GetStatus() const;
// Returns the information for all the modules that were loaded with
// symbol information.
std::vector<const LoadedModuleSymbols*> GetLoadedModuleSymbols() const;
// Converts the given InputLocation into one or more locations. The input
// can match zero, one, or many locations.
//
// If symbolize is true, the results will be symbolized, otherwise the
// output locations will be regular addresses (this will be slightly faster).
std::vector<Location> ResolveInputLocation(
const InputLocation& input_location,
const ResolveOptions& options = ResolveOptions()) const;
// Computes the line that corresponds to the given address. Unlike
// ResolveInputLocation (which just returns the current source line), this
// returns the entire set of contiguous line table entries with code ranges
// with the same line as the given address.
LineDetails LineDetailsForAddress(uint64_t address) const;
// Returns true if the code location is inside a module where there are
// symbols loaded. If we did something like index ELF exports, those wouldn't
// count. "Symbols loaded" here means there is real DWARF debugging
// information available.
bool HaveSymbolsLoadedForModuleAt(uint64_t address) const;
private:
struct ModuleInfo {
std::string name;
std::string build_id;
uint64_t base = 0;
// MAY BE NULL if the symbols could not be loaded.
//
// If this is ever extended to exist even if DWARF symbols can not be
// loaded (like we index ELF exports), be sure to update
// HaveSymbolsLoadedForModuleAt().
std::unique_ptr<LoadedModuleSymbols> symbols;
};
// Creates the ModuleInfo structure, attempts to load the symbols, and
// updates the modules_ list for this process. *err will be filled with the
// success code of symbol loading (the function will save the ModuleInfo
// either way).
//
// This class issues no notifications, the caller needs to do that. Just
// because there's no error doesn't necessarily mean the symbols have been
// loaded, since some symbols might be expected to be not present.
ModuleInfo* SaveModuleInfo(const debug_ipc::Module& module,
Err* symbol_load_err);
// Equality comparison for the two types of modules. This compares load
// address and build id.
static bool RefersToSameModule(const debug_ipc::Module& a,
const ModuleInfo& b);
// Looks up the given address and returns the module it's part of. Returns
// null if the address is out-of-range.
const ModuleInfo* InfoForAddress(uint64_t address) const;
Notifications* const notifications_; // Non-owning.
TargetSymbols* const target_symbols_; // Non-owning.
// Maps load address to the module symbol information.
using ModuleMap = std::map<uint64_t, ModuleInfo>;
ModuleMap modules_;
// Mutable so we can get weak pointers to a const object.
mutable fxl::WeakPtrFactory<const ProcessSymbols> weak_factory_;
FXL_DISALLOW_COPY_AND_ASSIGN(ProcessSymbols);
};
} // namespace zxdb