Files
swift-mirror/stdlib/public/runtime/ImageInspectionELF.cpp
Michael Gottesman 6bc28ff1c9 [strip -ST] Disable runtime stack trace dumping on Darwin when asserts are disabled.
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
2017-05-04 16:46:26 -06:00

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(&sectionInfo.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__)