mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This commit disables runtime stack trace dumping via dladdr on Darwin when asserts are disabled. This stack trace dumping was added as a way to improve the ability to debug the compiler for compiler developers. This is all well and good but having such a feature always enabled prevents us from reducing the size of the swift standard library by eliminating the swift nlist. rdar://31372220
182 lines
5.9 KiB
C++
182 lines
5.9 KiB
C++
//===--- ImageInspectionELF.cpp - ELF image inspection --------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file
|
|
///
|
|
/// This file includes routines that interact with ld*.so on ELF-based platforms
|
|
/// to extract runtime metadata embedded in dynamically linked ELF images
|
|
/// generated by the Swift compiler.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#if defined(__ELF__) || defined(__ANDROID__)
|
|
|
|
#include "ImageInspection.h"
|
|
#include "swift/Runtime/Debug.h"
|
|
#include <dlfcn.h>
|
|
#include <elf.h>
|
|
#include <link.h>
|
|
#include <string.h>
|
|
|
|
#ifndef SWIFT_RUNTIME_DLADDR_ALLOW
|
|
#error "SWIFT_RUNTIME_DLADDR_ALLOW must be defined!"
|
|
#endif
|
|
|
|
using namespace swift;
|
|
|
|
/// The symbol name in the image that identifies the beginning of the
|
|
/// protocol conformances table.
|
|
static const char ProtocolConformancesSymbol[] =
|
|
".swift2_protocol_conformances_start";
|
|
/// The symbol name in the image that identifies the beginning of the
|
|
/// type metadata record table.
|
|
static const char TypeMetadataRecordsSymbol[] =
|
|
".swift2_type_metadata_start";
|
|
|
|
/// Context arguments passed down from dl_iterate_phdr to its callback.
|
|
struct InspectArgs {
|
|
/// Symbol name to look up.
|
|
const char *symbolName;
|
|
/// Callback function to invoke with the metadata block.
|
|
void (*addBlock)(const void *start, uintptr_t size);
|
|
/// Set to true when initialize*Lookup() is called.
|
|
bool didInitializeLookup;
|
|
};
|
|
|
|
static InspectArgs ProtocolConformanceArgs = {
|
|
ProtocolConformancesSymbol,
|
|
addImageProtocolConformanceBlockCallback,
|
|
false
|
|
};
|
|
|
|
static InspectArgs TypeMetadataRecordArgs = {
|
|
TypeMetadataRecordsSymbol,
|
|
addImageTypeMetadataRecordBlockCallback,
|
|
false
|
|
};
|
|
|
|
|
|
// Extract the section information for a named section in an image. imageName
|
|
// can be nullptr to specify the main executable.
|
|
static SectionInfo getSectionInfo(const char *imageName,
|
|
const char *sectionName) {
|
|
SectionInfo sectionInfo = { 0, nullptr };
|
|
void *handle = dlopen(imageName, RTLD_LAZY | RTLD_NOLOAD);
|
|
if (!handle) {
|
|
fatalError(/* flags = */ 0, "dlopen() failed on `%s': %s", imageName,
|
|
dlerror());
|
|
}
|
|
void *symbol = dlsym(handle, sectionName);
|
|
if (symbol) {
|
|
// Extract the size of the section data from the head of the section.
|
|
const char *section = reinterpret_cast<const char *>(symbol);
|
|
memcpy(§ionInfo.size, section, sizeof(uint64_t));
|
|
sectionInfo.data = section + sizeof(uint64_t);
|
|
}
|
|
dlclose(handle);
|
|
return sectionInfo;
|
|
}
|
|
|
|
static int iteratePHDRCallback(struct dl_phdr_info *info,
|
|
size_t size, void *data) {
|
|
InspectArgs *inspectArgs = reinterpret_cast<InspectArgs *>(data);
|
|
const char *fname = info->dlpi_name;
|
|
|
|
// While dl_iterate_phdr() is in progress it holds a lock to prevent other
|
|
// images being loaded. The initialize flag is set here inside the callback so
|
|
// that addNewDSOImage() sees a consistent state. If it was set outside the
|
|
// dl_iterate_phdr() call then it could result in images being missed or
|
|
// added twice.
|
|
inspectArgs->didInitializeLookup = true;
|
|
|
|
if (fname == nullptr || fname[0] == '\0') {
|
|
// The filename may be null for both the dynamic loader and main executable.
|
|
// So ignore null image name here and explicitly add the main executable
|
|
// in initialize*Lookup() to avoid adding the data twice.
|
|
return 0;
|
|
}
|
|
|
|
SectionInfo block = getSectionInfo(fname, inspectArgs->symbolName);
|
|
if (block.size > 0) {
|
|
inspectArgs->addBlock(block.data, block.size);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Add the section information in an image specified by an address in that
|
|
// image.
|
|
static void addBlockInImage(const InspectArgs *inspectArgs, const void *addr) {
|
|
const char *fname = nullptr;
|
|
if (addr) {
|
|
Dl_info info;
|
|
if (dladdr(addr, &info) == 0 || info.dli_fname == nullptr) {
|
|
return;
|
|
}
|
|
fname = info.dli_fname;
|
|
}
|
|
SectionInfo block = getSectionInfo(fname, inspectArgs->symbolName);
|
|
if (block.size > 0) {
|
|
inspectArgs->addBlock(block.data, block.size);
|
|
}
|
|
}
|
|
|
|
static void initializeSectionLookup(InspectArgs *inspectArgs) {
|
|
// Add section data in the main executable.
|
|
addBlockInImage(inspectArgs, nullptr);
|
|
// Search the loaded dls. This only searches the already
|
|
// loaded ones. Any images loaded after this are processed by
|
|
// addNewDSOImage() below.
|
|
dl_iterate_phdr(iteratePHDRCallback, reinterpret_cast<void *>(inspectArgs));
|
|
}
|
|
|
|
void swift::initializeProtocolConformanceLookup() {
|
|
initializeSectionLookup(&ProtocolConformanceArgs);
|
|
}
|
|
|
|
void swift::initializeTypeMetadataRecordLookup() {
|
|
initializeSectionLookup(&TypeMetadataRecordArgs);
|
|
}
|
|
|
|
// As ELF images are loaded, ImageInspectionInit:sectionDataInit() will call
|
|
// addNewDSOImage() with an address in the image that can later be used via
|
|
// dladdr() to dlopen() the image after the appropriate initialize*Lookup()
|
|
// function has been called.
|
|
SWIFT_RUNTIME_EXPORT
|
|
void swift_addNewDSOImage(const void *addr) {
|
|
if (ProtocolConformanceArgs.didInitializeLookup) {
|
|
addBlockInImage(&ProtocolConformanceArgs, addr);
|
|
}
|
|
|
|
if (TypeMetadataRecordArgs.didInitializeLookup) {
|
|
addBlockInImage(&TypeMetadataRecordArgs, addr);
|
|
}
|
|
}
|
|
|
|
int swift::lookupSymbol(const void *address, SymbolInfo *info) {
|
|
#if SWIFT_RUNTIME_DLADDR_ALLOW
|
|
Dl_info dlinfo;
|
|
if (dladdr(address, &dlinfo) == 0) {
|
|
return 0;
|
|
}
|
|
|
|
info->fileName = dlinfo.dli_fname;
|
|
info->baseAddress = dlinfo.dli_fbase;
|
|
info->symbolName = dlinfo.dli_sname;
|
|
info->symbolAddress = dlinfo.dli_saddr;
|
|
return 1;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
#endif // defined(__ELF__) || defined(__ANDROID__)
|