blob: ae7451722a8d754ae985626c62d14e54b4e2a194 [file] [log] [blame]
//===-- DynamicLoaderMacOSXDYLD.h -------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// This is the DynamicLoader plugin for Darwin (macOS / iPhoneOS / tvOS /
// watchOS / BridgeOS)
// platforms earlier than 2016, where lldb would read the "dyld_all_image_infos"
// dyld internal structure to understand where things were loaded and the
// solib loaded/unloaded notification function we put a breakpoint on gives us
// an array of (load address, mod time, file path) tuples.
//
// As of late 2016, the new DynamicLoaderMacOS plugin should be used, which uses
// dyld SPI functions to get the same information without reading internal dyld
// data structures.
#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERMACOSXDYLD_H
#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERMACOSXDYLD_H
#include <mutex>
#include <vector>
#include "lldb/Host/SafeMachO.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/Process.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/StructuredData.h"
#include "lldb/Utility/UUID.h"
#include "DynamicLoaderDarwin.h"
class DynamicLoaderMacOSXDYLD : public lldb_private::DynamicLoaderDarwin {
public:
DynamicLoaderMacOSXDYLD(lldb_private::Process *process);
~DynamicLoaderMacOSXDYLD() override;
// Static Functions
static void Initialize();
static void Terminate();
static llvm::StringRef GetPluginNameStatic() { return "macosx-dyld"; }
static llvm::StringRef GetPluginDescriptionStatic();
static lldb_private::DynamicLoader *
CreateInstance(lldb_private::Process *process, bool force);
/// Called after attaching a process.
///
/// Allow DynamicLoader plug-ins to execute some code after
/// attaching to a process.
bool ProcessDidExec() override;
lldb_private::Status CanLoadImage() override;
bool GetSharedCacheInformation(
lldb::addr_t &base_address, lldb_private::UUID &uuid,
lldb_private::LazyBool &using_shared_cache,
lldb_private::LazyBool &private_shared_cache) override;
// PluginInterface protocol
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
bool IsFullyInitialized() override;
protected:
void PutToLog(lldb_private::Log *log) const;
void DoInitialImageFetch() override;
bool NeedToDoInitialImageFetch() override;
bool DidSetNotificationBreakpoint() override;
void DoClear() override;
bool ReadDYLDInfoFromMemoryAndSetNotificationCallback(lldb::addr_t addr);
static bool
NotifyBreakpointHit(void *baton,
lldb_private::StoppointCallbackContext *context,
lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
uint32_t AddrByteSize();
bool ReadMachHeader(lldb::addr_t addr, llvm::MachO::mach_header *header,
lldb_private::DataExtractor *load_command_data);
uint32_t ParseLoadCommands(const lldb_private::DataExtractor &data,
ImageInfo &dylib_info,
lldb_private::FileSpec *lc_id_dylinker);
struct DYLDAllImageInfos {
uint32_t version = 0;
uint32_t dylib_info_count = 0; // Version >= 1
lldb::addr_t dylib_info_addr = LLDB_INVALID_ADDRESS; // Version >= 1
lldb::addr_t notification = LLDB_INVALID_ADDRESS; // Version >= 1
bool processDetachedFromSharedRegion = false; // Version >= 1
bool libSystemInitialized = false; // Version >= 2
lldb::addr_t dyldImageLoadAddress = LLDB_INVALID_ADDRESS; // Version >= 2
DYLDAllImageInfos() = default;
void Clear() {
version = 0;
dylib_info_count = 0;
dylib_info_addr = LLDB_INVALID_ADDRESS;
notification = LLDB_INVALID_ADDRESS;
processDetachedFromSharedRegion = false;
libSystemInitialized = false;
dyldImageLoadAddress = LLDB_INVALID_ADDRESS;
}
bool IsValid() const { return version >= 1 && version <= 6; }
};
static lldb::ByteOrder GetByteOrderFromMagic(uint32_t magic);
bool SetNotificationBreakpoint() override;
void ClearNotificationBreakpoint() override;
// There is a little tricky bit where you might initially attach while dyld is
// updating
// the all_image_infos, and you can't read the infos, so you have to continue
// and pick it
// up when you hit the update breakpoint. At that point, you need to run this
// initialize
// function, but when you do it that way you DON'T need to do the extra work
// you would at
// the breakpoint.
// So this function will only do actual work if the image infos haven't been
// read yet.
// If it does do any work, then it will return true, and false otherwise.
// That way you can
// call it in the breakpoint action, and if it returns true you're done.
bool InitializeFromAllImageInfos();
bool ReadAllImageInfosStructure();
bool AddModulesUsingImageInfosAddress(lldb::addr_t image_infos_addr,
uint32_t image_infos_count);
bool RemoveModulesUsingImageInfosAddress(lldb::addr_t image_infos_addr,
uint32_t image_infos_count);
void UpdateImageInfosHeaderAndLoadCommands(ImageInfo::collection &image_infos,
uint32_t infos_count,
bool update_executable);
bool ReadImageInfos(lldb::addr_t image_infos_addr, uint32_t image_infos_count,
ImageInfo::collection &image_infos);
lldb::addr_t m_dyld_all_image_infos_addr;
DYLDAllImageInfos m_dyld_all_image_infos;
uint32_t m_dyld_all_image_infos_stop_id;
lldb::user_id_t m_break_id;
mutable std::recursive_mutex m_mutex;
bool m_process_image_addr_is_all_images_infos;
private:
DynamicLoaderMacOSXDYLD(const DynamicLoaderMacOSXDYLD &) = delete;
const DynamicLoaderMacOSXDYLD &
operator=(const DynamicLoaderMacOSXDYLD &) = delete;
};
#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERMACOSXDYLD_H