blob: 317599a763ab2a786c24c10c00de838709788f84 [file] [log] [blame]
// Copyright 2021 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_CLIENT_STEP_THROUGH_PLT_THREAD_CONTROLLER_H_
#define SRC_DEVELOPER_DEBUG_ZXDB_CLIENT_STEP_THROUGH_PLT_THREAD_CONTROLLER_H_
#include <vector>
#include "src/developer/debug/zxdb/client/step_through_plt_thread_controller.h"
#include "src/developer/debug/zxdb/client/until_thread_controller.h"
#include "src/developer/debug/zxdb/symbols/arch.h"
#include "src/lib/fxl/memory/weak_ptr.h"
namespace zxdb {
// The POSIX dynamic loader resolves cross-library symbols with "plt" trampolines. This is a small
// bit of code in the calling module. This code calls into the dynamic loader to resolve the symbol
// on demand. The PLT address is then replaced with the destination address to avoid future lookups.
//
// These PLT trampolines are unsymbolized and users normally want to ignore them. This thread
// controller can be instantiated for the first instruction in a PLT trampoline and it will get
// through the PLT trampoline and report a stop when the destination function is reached.
//
// When InitWithThread() is called, the thread should be stopped at a PLT trampoline.
class StepThroughPltThreadController : public ThreadController {
public:
explicit StepThroughPltThreadController() : weak_factory_(this) {}
// ThreadController implementation.
void InitWithThread(Thread* thread, fit::callback<void(const Err&)> cb) override;
ContinueOp GetContinueOp() override;
StopOp OnThreadStop(debug_ipc::ExceptionType stop_type,
const std::vector<fxl::WeakPtr<Breakpoint>>& hit_breakpoints) override;
const char* GetName() const override { return "Step Through PLT"; }
private:
void OnUntilControllerInitializationFailed();
// Address of the beginning of the PLT we're at.
uint64_t plt_address_ = 0;
// The destination address of this PLT trampoline. There can be multiple matches if the symbol
// lookup matches multiple locations, but one particular trampoline will match only one of these
// addresses.
std::vector<TargetPointer> dest_addrs_;
// This sub-controller handles stopping the thread at the destination of the call we computed.
//
// We prefer the "until" controller because the trampoline could do non-trivial work (dynamically
// resolving the destination) but fall back on single-stepping if it fails to initialize (the
// destination of the jump isn't writable). In that failure case the until_ member will be null
// and we'll step by instructions. Usually the PLTs are short enough where this is reasonable.
std::unique_ptr<ThreadController> until_;
fxl::WeakPtrFactory<StepThroughPltThreadController> weak_factory_;
};
} // namespace zxdb
#endif // SRC_DEVELOPER_DEBUG_ZXDB_CLIENT_STEP_THROUGH_PLT_THREAD_CONTROLLER_H_