[build] Don't export all symbols to the dynamic table.

We were exporting all symbols to the dynamic table so that they could be looked up using `dladdr` for the profiler and backtracer. The symbols include our statically-linked libcxx, which can create trouble when another DSO has a different version of libcxx. Now we export only the VM embedding API functions (`Dart_*`) and use a specially produced table to do the symbolization.

TEST=runtime/tests/vm/dart/exported_symbols_test.dart
TEST=runtime/tests/vm/dart/symbolized_crash_test.dart
Bug: https://github.com/dart-lang/sdk/issues/53267
Change-Id: I2ee494fba86f67127ba0f6f402622f01a4662207
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/323702
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ryan Macnak
2023-09-05 21:47:59 +00:00
committed by Commit Queue
parent ebc96ecb83
commit b8ee3a9996
22 changed files with 635 additions and 245 deletions
+4 -5
View File
@@ -264,11 +264,10 @@ if (is_win) {
]
}
if (is_posix) {
_native_compiler_configs += [ "//build/config/gcc:relative_paths" ]
if (is_product) {
_native_compiler_configs +=
[ "//build/config/gcc:symbol_visibility_hidden" ]
}
_native_compiler_configs += [
"//build/config/gcc:relative_paths",
"//build/config/gcc:symbol_visibility_hidden",
]
}
if (is_fuchsia) {
_native_compiler_configs += [
+4 -1
View File
@@ -137,18 +137,21 @@ toolchain("fuchsia") {
exename = "{{target_output_name}}{{output_extension}}"
outfile = "{{root_out_dir}}/$exename"
rspfile = "$outfile.rsp"
symfile = "$outfile.sym"
symbolizer_script = rebase_path("//runtime/tools/dart_profiler_symbols.py")
# Note that the unstripped_outfile is in the exe.stripped folder.
# We should probably clean this up, but changing this and dart.cmx
# to point ./dart instead of ./exe.stripped/dart makes the build
# fail because ./dart does not end up in the manifest file.
unstripped_outfile = "{{root_out_dir}}/exe.stripped/$exename"
command = "$compiler_prefix $ld $target_triple_flags $sysroot_flags $lto_flags {{ldflags}} -o $unstripped_outfile -Wl,--build-id -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}} && ${strip} -o $outfile $unstripped_outfile"
command = "$compiler_prefix $ld $target_triple_flags $sysroot_flags $lto_flags {{ldflags}} -o $unstripped_outfile -Wl,--build-id -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}} && ${strip} -o $outfile $unstripped_outfile && $symbolizer_script --nm $nm --output $symfile --binary $unstripped_outfile"
description = "LINK $outfile"
rspfile_content = "{{inputs}}"
outputs = [
unstripped_outfile,
outfile,
symfile,
]
}
+12 -1
View File
@@ -191,12 +191,20 @@ template("gcc_toolchain") {
exename = "{{target_output_name}}{{output_extension}}"
outfile = "{{root_out_dir}}/$exename"
rspfile = "$outfile.rsp"
symfile = "$outfile.sym"
if (defined(invoker.strip) || defined(invoker.llvm_objcopy)) {
stripped_outfile = "{{root_out_dir}}/exe.stripped/$exename"
}
command = "$ld {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group $libs_section_prefix {{libs}} $libs_section_postfix"
symbolizer_script =
rebase_path("//runtime/tools/dart_profiler_symbols.py")
symbolize_command =
"$symbolizer_script --nm $nm --output $symfile --binary $outfile"
command += " && $symbolize_command"
if (defined(invoker.strip)) {
strip = invoker.strip
strip_command =
@@ -212,7 +220,10 @@ template("gcc_toolchain") {
}
description = "LINK $outfile"
rspfile_content = "{{inputs}}"
outputs = [ outfile ]
outputs = [
outfile,
symfile,
]
if (defined(invoker.strip) || defined(invoker.llvm_objcopy)) {
outputs += [ stripped_outfile ]
}
+15 -1
View File
@@ -49,6 +49,7 @@ template("mac_toolchain") {
cxx = invoker.cxx
ar = invoker.ar
ld = invoker.ld
nm = invoker.nm
# Make these apply to all tools below.
lib_switch = "-l"
@@ -175,12 +176,20 @@ template("mac_toolchain") {
exename = "{{target_output_name}}{{output_extension}}"
outfile = "{{root_out_dir}}/$exename"
rspfile = "$outfile.rsp"
symfile = "$outfile.sym"
if (defined(invoker.strip)) {
stripped_outfile = "{{root_out_dir}}/exe.stripped/$exename"
}
command = "$ld $sysroot_flags $toolchain_flags {{ldflags}} -Xlinker -rpath -Xlinker @executable_path/Frameworks -o $outfile -Wl,-filelist,$rspfile {{solibs}} {{libs}} {{frameworks}}"
symbolizer_script =
rebase_path("//runtime/tools/dart_profiler_symbols.py")
symbolize_command =
"$symbolizer_script --nm $nm --output $symfile --binary $outfile"
command += " && $symbolize_command"
if (defined(invoker.strip)) {
strip = invoker.strip
strip_command = "${strip} -x -o $stripped_outfile $outfile"
@@ -189,7 +198,10 @@ template("mac_toolchain") {
description = "LINK $outfile"
rspfile_content = "{{inputs_newline}}"
outputs = [ outfile ]
outputs = [
outfile,
symfile,
]
if (defined(invoker.strip)) {
outputs += [ stripped_outfile ]
}
@@ -229,6 +241,7 @@ mac_toolchain("clang_x64") {
ar = "${prefix}/llvm-ar"
ld = cxx
strip = "${prefix}/llvm-strip"
nm = "${prefix}/llvm-nm"
is_clang = true
if (mac_enable_relative_sdk_path) {
mac_sdk_path = rebase_path(mac_sdk_path, root_build_dir)
@@ -245,6 +258,7 @@ mac_toolchain("clang_arm64") {
ar = "${prefix}/llvm-ar"
ld = cxx
strip = "${prefix}/llvm-strip"
nm = "${prefix}/llvm-nm"
is_clang = true
if (mac_enable_relative_sdk_path) {
mac_sdk_path = rebase_path(mac_sdk_path, root_build_dir)
+35 -14
View File
@@ -204,11 +204,18 @@ template("build_gen_snapshot") {
]
}
if (!is_win) {
# Adds all symbols to the dynamic symbol table, not just used ones.
# This is needed to make native extensions work. It is also needed to get
# symbols in VM-generated backtraces and profiles.
ldflags = [ "-rdynamic" ]
if (is_mac) {
ldflags = [
"-Wl,-exported_symbol",
"-Wl,_Dart_*",
]
} else if (!is_win) {
if (!is_clang) {
# TODO(rmacnak): Remove once bots are updated to a newer gcc.
ldflags = [ "-rdynamic" ]
} else {
ldflags = [ "-Wl,--export-dynamic-symbol=Dart_*" ]
}
}
if (is_win) {
@@ -793,11 +800,18 @@ template("dart_executable") {
if (is_win) {
ldflags = [ "/EXPORT:Dart_True" ]
} else if (is_mac) {
ldflags = [
"-Wl,-exported_symbol",
"-Wl,_Dart_*",
]
} else {
# Adds all symbols to the dynamic symbol table, not just used ones.
# This is needed to make native extensions work. It is also needed to get
# symbols in VM-generated backtraces and profiles.
ldflags = [ "-rdynamic" ]
if (!is_clang) {
# TODO(rmacnak): Remove once bots are updated to a newer gcc.
ldflags = [ "-rdynamic" ]
} else {
ldflags = [ "-Wl,--export-dynamic-symbol=Dart_*" ]
}
}
ldflags += extra_ldflags
@@ -1018,11 +1032,18 @@ executable("run_vm_tests") {
] + builtin_impl_tests + vm_tests + compiler_tests + heap_tests +
io_impl_tests
if (!is_win) {
# Adds all symbols to the dynamic symbol table, not just used ones.
# This is needed to make native extensions work. It is also needed to get
# symbols in VM-generated backtraces and profiles.
ldflags = [ "-rdynamic" ]
if (is_mac) {
ldflags = [
"-Wl,-exported_symbol",
"-Wl,_Dart_*",
]
} else if (!is_win) {
if (!is_clang) {
# TODO(rmacnak): Remove once bots are updated to a newer gcc.
ldflags = [ "-rdynamic" ]
} else {
ldflags = [ "-Wl,--export-dynamic-symbol=Dart_*" ]
}
}
if (is_win) {
+19
View File
@@ -121,5 +121,24 @@ Utils::CStringUniquePtr EXEUtils::GetDirectoryPrefixFromExeName() {
: result);
}
#if !defined(DART_HOST_OS_WINDOWS)
void EXEUtils::LoadDartProfilerSymbols(const char* exepath) {
int len = strlen(exepath);
char* sympath = reinterpret_cast<char*>(malloc(len + 5));
memcpy(sympath, exepath, len); // NOLINT
memcpy(sympath + len, ".sym", 5); // NOLINT
File* file = File::Open(nullptr, sympath, File::kRead);
free(sympath);
if (file != nullptr) {
int64_t size = file->Length();
MappedMemory* mapping = file->Map(File::kReadOnly, 0, size);
Dart_AddSymbols(exepath, mapping->address(), size);
mapping->Leak(); // Let us delete the object but keep the mapping.
delete mapping;
file->Release();
}
}
#endif // !defined(DART_HOST_OS_WINDOWS)
} // namespace bin
} // namespace dart
+6
View File
@@ -20,6 +20,12 @@ class EXEUtils {
// Returns the path to the directory the current executable resides in.
static Utils::CStringUniquePtr GetDirectoryPrefixFromExeName();
#if !defined(DART_HOST_OS_WINDOWS)
// Loads a compact symbolization table from "$exepath.sym" that is used by the
// VM's profiler and crash stack trace dumper to symbolize C frames.
static void LoadDartProfilerSymbols(const char* exepath);
#endif
private:
DISALLOW_COPY_AND_ASSIGN(EXEUtils);
};
+2
View File
@@ -35,6 +35,8 @@ class MappedMemory {
intptr_t size() const { return size_; }
uword start() const { return reinterpret_cast<uword>(address()); }
void Leak() { should_unmap_ = false; }
private:
void Unmap();
+6
View File
@@ -17,6 +17,7 @@
#include "bin/dartutils.h"
#include "bin/error_exit.h"
#include "bin/eventhandler.h"
#include "bin/exe_utils.h"
#include "bin/file.h"
#include "bin/loader.h"
#include "bin/options.h"
@@ -844,6 +845,11 @@ static int CreateIsolateAndSnapshot(const CommandLineOptions& inputs) {
}
int main(int argc, char** argv) {
#if !defined(DART_HOST_OS_WINDOWS)
// Very early so any crashes during startup can also be symbolized.
EXEUtils::LoadDartProfilerSymbols(argv[0]);
#endif
const int EXTRA_VM_ARGUMENTS = 7;
CommandLineOptions vm_options(argc + EXTRA_VM_ARGUMENTS);
CommandLineOptions inputs(argc);
+6
View File
@@ -19,6 +19,7 @@
#include "bin/dfe.h"
#include "bin/error_exit.h"
#include "bin/eventhandler.h"
#include "bin/exe_utils.h"
#include "bin/file.h"
#include "bin/gzip.h"
#include "bin/isolate_data.h"
@@ -1152,6 +1153,11 @@ static Dart_GetVMServiceAssetsArchive GetVMServiceAssetsArchiveCallback =
#endif // !defined(PRODUCT)
void main(int argc, char** argv) {
#if !defined(DART_HOST_OS_WINDOWS)
// Very early so any crashes during startup can also be symbolized.
EXEUtils::LoadDartProfilerSymbols(argv[0]);
#endif
char* script_name = nullptr;
// Allows the dartdev process to point to the desired package_config.
char* package_config_override = nullptr;
+6
View File
@@ -7,6 +7,7 @@
#include "bin/dartutils.h"
#include "bin/dfe.h"
#include "bin/eventhandler.h"
#include "bin/exe_utils.h"
#include "bin/file.h"
#include "bin/loader.h"
#include "bin/platform.h"
@@ -293,6 +294,11 @@ void ShiftArgs(int* argc, const char** argv) {
}
static int Main(int argc, const char** argv) {
#if !defined(DART_HOST_OS_WINDOWS)
// Very early so any crashes during startup can also be symbolized.
bin::EXEUtils::LoadDartProfilerSymbols(argv[0]);
#endif
// Flags being passed to the Dart VM.
int dart_argc = 0;
const char** dart_argv = nullptr;
@@ -0,0 +1,338 @@
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import "dart:io";
import "package:expect/expect.dart";
main() {
if (Platform.isWindows) return;
if (Platform.isAndroid) return; // no nm available on test device
var result = Process.runSync("nm", [
Platform.isMacOS ? "--extern-only" : "--dynamic",
"--defined-only",
"--format=posix",
Platform.executable
]);
if (result.exitCode != 0) {
print("nm failed");
print(result.stdout);
print(result.stderr);
throw "nm failed";
}
var symbols = result.stdout.split("\n")..remove("");
for (var i = 0; i < symbols.length; i++) {
// Get just the symbol name. Old nm on bots doesn't have --just-symbols.
symbols[i] = symbols[i].split(" ")[0];
if (Platform.isMacOS) {
// Remove leading underscores.
symbols[i] = symbols[i].substring(1);
}
}
symbols.remove("_IO_stdin_used"); // Only on IA32 for libc.
print(symbols);
Expect.setEquals(symbols, [
"Dart_AddSymbols",
"Dart_Allocate",
"Dart_AllocateWithNativeFields",
"Dart_BooleanValue",
"Dart_ClassLibrary",
"Dart_ClassName",
"Dart_Cleanup",
"Dart_CloseNativePort",
"Dart_ClosureFunction",
"Dart_CompileAll",
"Dart_CompileToKernel",
"Dart_CreateAppAOTSnapshotAsAssemblies",
"Dart_CreateAppAOTSnapshotAsAssembly",
"Dart_CreateAppAOTSnapshotAsElf",
"Dart_CreateAppAOTSnapshotAsElfs",
"Dart_CreateAppJITSnapshotAsBlobs",
"Dart_CreateCoreJITSnapshotAsBlobs",
"Dart_CreateIsolateGroup",
"Dart_CreateIsolateGroupFromKernel",
"Dart_CreateIsolateInGroup",
"Dart_CreateSnapshot",
"Dart_CreateVMAOTSnapshotAsAssembly",
"Dart_CurrentIsolate",
"Dart_CurrentIsolateData",
"Dart_CurrentIsolateGroup",
"Dart_CurrentIsolateGroupData",
"Dart_CurrentIsolateGroupId",
"Dart_DebugName",
"Dart_DebugNameToCString",
"Dart_DefaultCanonicalizeUrl",
"Dart_DeferredLoadComplete",
"Dart_DeferredLoadCompleteError",
"Dart_DeleteFinalizableHandle",
"Dart_DeletePersistentHandle",
"Dart_DeleteWeakPersistentHandle",
"Dart_DetectNullSafety",
"Dart_DisableHeapSampling",
"Dart_DoubleValue",
"Dart_DumpNativeStackTrace",
"Dart_EmptyString",
"Dart_EnableHeapSampling",
"Dart_EnterIsolate",
"Dart_EnterScope",
"Dart_ErrorGetException",
"Dart_ErrorGetStackTrace",
"Dart_ErrorHasException",
"Dart_ExecuteInternalCommand",
"Dart_ExitIsolate",
"Dart_ExitScope",
"Dart_False",
"Dart_FinalizeAllClasses",
"Dart_FinalizeLoading",
"Dart_FunctionIsStatic",
"Dart_FunctionName",
"Dart_FunctionOwner",
"Dart_GetClass",
"Dart_GetCurrentUserTag",
"Dart_GetDataFromByteBuffer",
"Dart_GetDefaultUserTag",
"Dart_GetError",
"Dart_GetField",
"Dart_GetLoadedLibraries",
"Dart_GetMainPortId",
"Dart_GetMessageNotifyCallback",
"Dart_GetNativeArgument",
"Dart_GetNativeArgumentCount",
"Dart_GetNativeArguments",
"Dart_GetNativeBooleanArgument",
"Dart_GetNativeDoubleArgument",
"Dart_GetNativeFieldsOfArgument",
"Dart_GetNativeInstanceField",
"Dart_GetNativeInstanceFieldCount",
"Dart_GetNativeIntegerArgument",
"Dart_GetNativeIsolateGroupData",
"Dart_GetNativeReceiver",
"Dart_GetNativeResolver",
"Dart_GetNativeStringArgument",
"Dart_GetNativeSymbol",
"Dart_GetNonNullableType",
"Dart_GetNullableType",
"Dart_GetObfuscationMap",
"Dart_GetPeer",
"Dart_GetStaticMethodClosure",
"Dart_GetStickyError",
"Dart_GetType",
"Dart_GetTypeOfExternalTypedData",
"Dart_GetTypeOfTypedData",
"Dart_GetUserTagLabel",
"Dart_HandleFromPersistent",
"Dart_HandleFromWeakPersistent",
"Dart_HandleMessage",
"Dart_HandleServiceMessages",
"Dart_HasLivePorts",
"Dart_HasServiceMessages",
"Dart_HasStickyError",
"Dart_IdentityEquals",
"Dart_Initialize",
"Dart_InstanceGetType",
"Dart_IntegerFitsIntoInt64",
"Dart_IntegerFitsIntoUint64",
"Dart_IntegerToHexCString",
"Dart_IntegerToInt64",
"Dart_IntegerToUint64",
"Dart_Invoke",
"Dart_InvokeClosure",
"Dart_InvokeConstructor",
"Dart_InvokeVMServiceMethod",
"Dart_IsApiError",
"Dart_IsBoolean",
"Dart_IsByteBuffer",
"Dart_IsClosure",
"Dart_IsCompilationError",
"Dart_IsDouble",
"Dart_IsError",
"Dart_IsExternalString",
"Dart_IsFatalError",
"Dart_IsFunction",
"Dart_IsFuture",
"Dart_IsInstance",
"Dart_IsInteger",
"Dart_IsKernel",
"Dart_IsKernelIsolate",
"Dart_IsLegacyType",
"Dart_IsLibrary",
"Dart_IsList",
"Dart_IsMap",
"Dart_IsNonNullableType",
"Dart_IsNull",
"Dart_IsNullableType",
"Dart_IsNumber",
"Dart_IsolateData",
"Dart_IsolateFlagsInitialize",
"Dart_IsolateGroupData",
"Dart_IsolateGroupHeapNewCapacityMetric",
"Dart_IsolateGroupHeapNewExternalMetric",
"Dart_IsolateGroupHeapNewUsedMetric",
"Dart_IsolateGroupHeapOldCapacityMetric",
"Dart_IsolateGroupHeapOldExternalMetric",
"Dart_IsolateGroupHeapOldUsedMetric",
"Dart_IsolateMakeRunnable",
"Dart_IsolateRunnableHeapSizeMetric",
"Dart_IsolateRunnableLatencyMetric",
"Dart_IsolateServiceId",
"Dart_IsPausedOnExit",
"Dart_IsPausedOnStart",
"Dart_IsPrecompiledRuntime",
"Dart_IsReloading",
"Dart_IsServiceIsolate",
"Dart_IsString",
"Dart_IsStringLatin1",
"Dart_IsTearOff",
"Dart_IsType",
"Dart_IsTypedData",
"Dart_IsTypeVariable",
"Dart_IsUnhandledExceptionError",
"Dart_IsVariable",
"Dart_IsVMFlagSet",
"Dart_KernelIsolateIsRunning",
"Dart_KernelListDependencies",
"Dart_KernelPort",
"Dart_KillIsolate",
"Dart_LibraryHandleError",
"Dart_LibraryResolvedUrl",
"Dart_LibraryUrl",
"Dart_ListGetAsBytes",
"Dart_ListGetAt",
"Dart_ListGetRange",
"Dart_ListLength",
"Dart_ListSetAsBytes",
"Dart_ListSetAt",
"Dart_LoadingUnitLibraryUris",
"Dart_LoadLibrary",
"Dart_LoadLibraryFromKernel",
"Dart_LoadScriptFromKernel",
"Dart_LookupLibrary",
"Dart_MapContainsKey",
"Dart_MapGetAt",
"Dart_MapKeys",
"Dart_New",
"Dart_NewApiError",
"Dart_NewBoolean",
"Dart_NewByteBuffer",
"Dart_NewCompilationError",
"Dart_NewDouble",
"Dart_NewExternalLatin1String",
"Dart_NewExternalTypedData",
"Dart_NewExternalTypedDataWithFinalizer",
"Dart_NewExternalUTF16String",
"Dart_NewFinalizableHandle",
"Dart_NewInteger",
"Dart_NewIntegerFromHexCString",
"Dart_NewIntegerFromUint64",
"Dart_NewList",
"Dart_NewListOf",
"Dart_NewListOfType",
"Dart_NewListOfTypeFilled",
"Dart_NewNativePort",
"Dart_NewPersistentHandle",
"Dart_NewSendPort",
"Dart_NewStringFromCString",
"Dart_NewStringFromUTF16",
"Dart_NewStringFromUTF32",
"Dart_NewStringFromUTF8",
"Dart_NewTypedData",
"Dart_NewUnhandledExceptionError",
"Dart_NewUnmodifiableExternalTypedDataWithFinalizer",
"Dart_NewUserTag",
"Dart_NewWeakPersistentHandle",
"Dart_NotifyDestroyed",
"Dart_NotifyIdle",
"Dart_NotifyLowMemory",
"Dart_Null",
"Dart_ObjectEquals",
"Dart_ObjectIsType",
"Dart_Post",
"Dart_PostCObject",
"Dart_PostInteger",
"Dart_Precompile",
"Dart_PrepareToAbort",
"Dart_PropagateError",
"Dart_RecordTimelineEvent",
"Dart_RegisterHeapSamplingCallback",
"Dart_RegisterIsolateServiceRequestCallback",
"Dart_RegisterRootServiceRequestCallback",
"Dart_ReportSurvivingAllocations",
"Dart_ReThrowException",
"Dart_RootLibrary",
"Dart_RunLoop",
"Dart_RunLoopAsync",
"Dart_ScopeAllocate",
"Dart_SendPortGetId",
"Dart_ServiceSendDataEvent",
"Dart_SetBooleanReturnValue",
"Dart_SetCurrentUserTag",
"Dart_SetDartLibrarySourcesKernel",
"Dart_SetDeferredLoadHandler",
"Dart_SetDoubleReturnValue",
"Dart_SetDwarfStackTraceFootnoteCallback",
"Dart_SetEmbedderInformationCallback",
"Dart_SetEnabledTimelineCategory",
"Dart_SetEnvironmentCallback",
"Dart_SetFfiNativeResolver",
"Dart_SetField",
"Dart_SetFileModifiedCallback",
"Dart_SetHeapSamplingPeriod",
"Dart_SetIntegerReturnValue",
"Dart_SetLibraryTagHandler",
"Dart_SetMessageNotifyCallback",
"Dart_SetNativeInstanceField",
"Dart_SetNativeResolver",
"Dart_SetPausedOnExit",
"Dart_SetPausedOnStart",
"Dart_SetPeer",
"Dart_SetPerformanceMode",
"Dart_SetPersistentHandle",
"Dart_SetReturnValue",
"Dart_SetRootLibrary",
"Dart_SetServiceStreamCallbacks",
"Dart_SetShouldPauseOnExit",
"Dart_SetShouldPauseOnStart",
"Dart_SetStickyError",
"Dart_SetThreadName",
"Dart_SetTimelineRecorderCallback",
"Dart_SetVMFlags",
"Dart_SetWeakHandleReturnValue",
"Dart_ShouldPauseOnExit",
"Dart_ShouldPauseOnStart",
"Dart_ShutdownIsolate",
"Dart_SortClasses",
"Dart_StartProfiling",
"Dart_StopProfiling",
"Dart_StringGetProperties",
"Dart_StringLength",
"Dart_StringStorageSize",
"Dart_StringToCString",
"Dart_StringToLatin1",
"Dart_StringToUTF16",
"Dart_StringToUTF8",
"Dart_ThreadDisableProfiling",
"Dart_ThreadEnableProfiling",
"Dart_ThrowException",
"Dart_TimelineEvent",
"Dart_TimelineGetMicros",
"Dart_TimelineGetTicks",
"Dart_TimelineGetTicksFrequency",
"Dart_ToString",
"Dart_True",
"Dart_TypedDataAcquireData",
"Dart_TypedDataReleaseData",
"Dart_TypeDynamic",
"Dart_TypeNever",
"Dart_TypeToNonNullableType",
"Dart_TypeToNullableType",
"Dart_TypeVoid",
"Dart_VersionString",
"Dart_WaitForEvent",
"Dart_WriteHeapSnapshot",
"Dart_WriteProfileToTimeline",
]);
}
@@ -0,0 +1,30 @@
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import "dart:io";
import 'package:expect/expect.dart';
import 'package:path/path.dart' as path;
main() {
if (Platform.isWindows) return; // posix exit codes
if (Platform.isAndroid) return; // run_vm_tests not available on test device
var run_vm_tests =
path.join(path.dirname(Platform.resolvedExecutable), "run_vm_tests");
var result = Process.runSync(run_vm_tests, ["Fatal"]);
print(result.exitCode);
print(result.stdout);
print(result.stderr);
Expect.contains(
"error: This test fails and produces a backtrace", result.stderr);
// Check for the frames that are marked never inline or have their address
// taken, and so should be stable to changes in the C compiler. There are of
// course more frames.
Expect.contains("dart::Assert::Fail", result.stderr);
Expect.contains("Dart_TestFatal", result.stderr);
Expect.contains("main", result.stderr);
}
+93
View File
@@ -0,0 +1,93 @@
#!/usr/bin/env python3
# Copyright 2013 The Flutter Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# On Fuchsia, in lieu of the ELF dynamic symbol table consumed through dladdr,
# the Dart VM profiler consumes symbols produced by this tool, which have the
# format
#
# struct {
# uint32_t num_entries;
# struct {
# uint32_t offset;
# uint32_t size;
# uint32_t string_table_offset;
# } entries[num_entries];
# const char* string_table;
# }
#
# Entries are sorted by offset. String table entries are NUL-terminated.
#
# See also //third_party/dart/runtime/vm/native_symbol_fuchsia.cc
import optparse
import os
import re
import utils
import subprocess
import struct
class Symbol:
def __init__(self, offset, size, name):
self.offset = offset
self.size = size
self.name = name
parser = optparse.OptionParser()
parser.add_option("--nm", type="string", help="Path to `nm` tool")
parser.add_option("--binary", type="string")
parser.add_option("--output", type="string")
options = parser.parse_args()[0]
nm = options.nm
if not nm:
raise Exception('--nm not specified')
binary = options.binary
if not binary:
raise Exception('--binary not specified')
output = options.output
if not output:
raise Exception('--output not specified')
p = subprocess.Popen(
[nm, "--demangle", "--numeric-sort", "--print-size", binary],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
nm_output, _ = p.communicate()
nm_lines = nm_output.decode('utf-8').split('\n')
regex = re.compile("([0-9A-Za-z]+) ([0-9A-Za-z]+) (t|T|w|W) (.*)")
symbols = []
for line in nm_lines:
m = regex.match(line)
if not m:
continue
offset = int(m.group(1), 16)
if offset > 0x100000000:
# Mac adds an extra 4GB for some reason
offset -= 0x100000000
size = int(m.group(2), 16)
name = m.group(4).split("(")[0]
if name == "__mh_execute_header":
# Skip very out-of-range thing.
continue
symbols.append(Symbol(offset, size, name.encode('utf-8')))
if len(symbols) == 0:
raise Exception(binary + " has no symbols")
stream = open(output, "wb")
stream.write(struct.pack("I", len(symbols)))
nameOffset = 0
for symbol in symbols:
stream.write(struct.pack("I", symbol.offset))
stream.write(struct.pack("I", symbol.size))
stream.write(struct.pack("I", nameOffset))
nameOffset += len(symbol.name)
nameOffset += 1
for symbol in symbols:
stream.write(symbol.name)
stream.write(b"\0")
stream.close()
+4
View File
@@ -54,3 +54,7 @@ VM_UNIT_TEST_CASE(Fail1) {
VM_UNIT_TEST_CASE(Fail2) {
FAIL("This test fails with two arguments: %d, %d", -100, 42);
}
VM_UNIT_TEST_CASE_WITH_EXPECTATION(Fatal, "Crash") {
FATAL("This test fails and produces a backtrace");
}
-71
View File
@@ -1,71 +0,0 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "platform/globals.h"
#if defined(DART_HOST_OS_ANDROID)
#include "vm/native_symbol.h"
#include "vm/os.h"
#include <cxxabi.h> // NOLINT
#include <dlfcn.h> // NOLINT
namespace dart {
void NativeSymbolResolver::Init() {}
void NativeSymbolResolver::Cleanup() {}
char* NativeSymbolResolver::LookupSymbolName(uword pc, uword* start) {
Dl_info info;
int r = dladdr(reinterpret_cast<void*>(pc), &info);
if (r == 0) {
return nullptr;
}
if (info.dli_sname == nullptr) {
return nullptr;
}
if (start != nullptr) {
*start = reinterpret_cast<uword>(info.dli_saddr);
}
int status = 0;
size_t len = 0;
char* demangled = abi::__cxa_demangle(info.dli_sname, nullptr, &len, &status);
MSAN_UNPOISON(demangled, len);
if (status == 0) {
return demangled;
}
return strdup(info.dli_sname);
}
void NativeSymbolResolver::FreeSymbolName(char* name) {
free(name);
}
bool NativeSymbolResolver::LookupSharedObject(uword pc,
uword* dso_base,
char** dso_name) {
Dl_info info;
int r = dladdr(reinterpret_cast<void*>(pc), &info);
if (r == 0) {
return false;
}
if (dso_base != nullptr) {
*dso_base = reinterpret_cast<uword>(info.dli_fbase);
}
if (dso_name != nullptr) {
*dso_name = strdup(info.dli_fname);
}
return true;
}
void NativeSymbolResolver::AddSymbols(const char* dso_name,
void* buffer,
size_t size) {
OS::PrintErr("warning: Dart_AddSymbols has no effect on Android\n");
}
} // namespace dart
#endif // defined(DART_HOST_OS_ANDROID)
-72
View File
@@ -1,72 +0,0 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/globals.h"
#if defined(DART_HOST_OS_LINUX)
#include "platform/memory_sanitizer.h"
#include "vm/native_symbol.h"
#include "vm/os.h"
#include <cxxabi.h> // NOLINT
#include <dlfcn.h> // NOLINT
namespace dart {
void NativeSymbolResolver::Init() {}
void NativeSymbolResolver::Cleanup() {}
char* NativeSymbolResolver::LookupSymbolName(uword pc, uword* start) {
Dl_info info;
int r = dladdr(reinterpret_cast<void*>(pc), &info);
if (r == 0) {
return nullptr;
}
if (info.dli_sname == nullptr) {
return nullptr;
}
if (start != nullptr) {
*start = reinterpret_cast<uword>(info.dli_saddr);
}
int status = 0;
size_t len = 0;
char* demangled = abi::__cxa_demangle(info.dli_sname, nullptr, &len, &status);
MSAN_UNPOISON(demangled, len);
if (status == 0) {
return demangled;
}
return strdup(info.dli_sname);
}
void NativeSymbolResolver::FreeSymbolName(char* name) {
free(name);
}
bool NativeSymbolResolver::LookupSharedObject(uword pc,
uword* dso_base,
char** dso_name) {
Dl_info info;
int r = dladdr(reinterpret_cast<void*>(pc), &info);
if (r == 0) {
return false;
}
if (dso_base != nullptr) {
*dso_base = reinterpret_cast<uword>(info.dli_fbase);
}
if (dso_name != nullptr) {
*dso_name = strdup(info.dli_fname);
}
return true;
}
void NativeSymbolResolver::AddSymbols(const char* dso_name,
void* buffer,
size_t size) {
OS::PrintErr("warning: Dart_AddSymbols has no effect on Linux\n");
}
} // namespace dart
#endif // defined(DART_HOST_OS_LINUX)
-70
View File
@@ -1,70 +0,0 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/globals.h"
#if defined(DART_HOST_OS_MACOS)
#include "vm/native_symbol.h"
#include "vm/os.h"
#include <cxxabi.h> // NOLINT
#include <dlfcn.h> // NOLINT
namespace dart {
void NativeSymbolResolver::Init() {}
void NativeSymbolResolver::Cleanup() {}
char* NativeSymbolResolver::LookupSymbolName(uword pc, uword* start) {
Dl_info info;
int r = dladdr(reinterpret_cast<void*>(pc), &info);
if (r == 0) {
return nullptr;
}
if (info.dli_sname == nullptr) {
return nullptr;
}
if (start != nullptr) {
*start = reinterpret_cast<uword>(info.dli_saddr);
}
int status;
char* demangled =
abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
if (status == 0) {
return demangled;
}
return strdup(info.dli_sname);
}
void NativeSymbolResolver::FreeSymbolName(char* name) {
free(name);
}
bool NativeSymbolResolver::LookupSharedObject(uword pc,
uword* dso_base,
char** dso_name) {
Dl_info info;
int r = dladdr(reinterpret_cast<void*>(pc), &info);
if (r == 0) {
return false;
}
if (dso_base != nullptr) {
*dso_base = reinterpret_cast<uword>(info.dli_fbase);
}
if (dso_name != nullptr) {
*dso_name = strdup(info.dli_fname);
}
return true;
}
void NativeSymbolResolver::AddSymbols(const char* dso_name,
void* buffer,
size_t size) {
OS::PrintErr("warning: Dart_AddSymbols has no effect on MacOS\n");
}
} // namespace dart
#endif // defined(DART_HOST_OS_MACOS)
@@ -1,13 +1,15 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/globals.h"
#if defined(DART_HOST_OS_FUCHSIA)
#if defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA) || \
defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS)
#include "platform/memory_sanitizer.h"
#include "vm/native_symbol.h"
#include <cxxabi.h> // NOLINT
#include <dlfcn.h> // NOLINT
namespace dart {
@@ -124,7 +126,26 @@ char* NativeSymbolResolver::LookupSymbolName(uword pc, uword* start) {
}
}
#if !defined(DART_HOST_OS_FUCHSIA)
// Fallback for libc, etc.
if (info.dli_sname == nullptr) {
return nullptr;
}
if (start != nullptr) {
*start = reinterpret_cast<uword>(info.dli_saddr);
}
int status = 0;
size_t len = 0;
char* demangled = abi::__cxa_demangle(info.dli_sname, nullptr, &len, &status);
MSAN_UNPOISON(demangled, len);
if (status == 0) {
return demangled;
}
return strdup(info.dli_sname);
#else
// Never works on Fuchsia; avoid linking in cxa_demangle.
return nullptr;
#endif
}
void NativeSymbolResolver::FreeSymbolName(char* name) {
@@ -149,7 +170,8 @@ bool NativeSymbolResolver::LookupSharedObject(uword pc,
}
void NativeSymbolResolver::AddSymbols(const char* dso_name,
void* buffer, size_t size) {
void* buffer,
size_t size) {
NativeSymbols* symbols = new NativeSymbols(dso_name, buffer, size);
symbols->set_next(symbols_);
symbols_ = symbols;
@@ -157,4 +179,5 @@ void NativeSymbolResolver::AddSymbols(const char* dso_name,
} // namespace dart
#endif // defined(DART_HOST_OS_FUCHSIA)
#endif // defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA) || \
// defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS)
+6 -1
View File
@@ -71,7 +71,12 @@ ProfilerCounters Profiler::counters_ = {};
static void DumpStackFrame(intptr_t frame_index, uword pc, uword fp) {
uword start = 0;
if (auto const name = NativeSymbolResolver::LookupSymbolName(pc, &start)) {
// The pc for all frames except the top frame is a return address, which can
// belong to a different inlining interval than the call. Subtract one to get
// the symbolization for the call.
uword lookup_pc = frame_index == 0 ? pc : pc - 1;
if (auto const name =
NativeSymbolResolver::LookupSymbolName(lookup_pc, &start)) {
uword offset = pc - start;
OS::PrintErr(" pc 0x%" Pp " fp 0x%" Pp " %s+0x%" Px "\n", pc, fp, name,
offset);
+1 -4
View File
@@ -179,10 +179,7 @@ vm_sources = [
"native_message_handler.cc",
"native_message_handler.h",
"native_symbol.h",
"native_symbol_android.cc",
"native_symbol_fuchsia.cc",
"native_symbol_linux.cc",
"native_symbol_macos.cc",
"native_symbol_posix.cc",
"native_symbol_win.cc",
"object.cc",
"object.h",
+21 -1
View File
@@ -261,6 +261,8 @@ copy_trees("copy_trees") {
sources = copy_tree_specs
}
_has_dot_sym = !is_win && rebase_path(".") == rebase_path("//sdk")
# Copies the Dart VM binary into bin/
if (target_os != current_os && target_os == "fuchsia") {
# In the Fuchsia build, this has to use a symlink for two reasons.
@@ -298,6 +300,9 @@ if (target_os != current_os && target_os == "fuchsia") {
if (is_win && dart_lib_export_symbols) {
sources += [ "$dart_out/dart.lib" ]
}
if (_has_dot_sym) {
sources += [ "$dart_out/dart.sym" ]
}
outputs = [ "$root_out_dir/$dart_sdk_output/bin/{{source_file_part}}" ]
}
}
@@ -315,8 +320,15 @@ copy("copy_dartaotruntime") {
]
}
copy("copy_gen_snapshot") {
group("copy_gen_snapshot") {
visibility = [ ":group_dart2native" ]
public_deps = [ ":copy_gen_snapshot_exe" ]
if (_has_dot_sym) {
public_deps += [ ":copy_gen_snapshot_sym" ]
}
}
copy("copy_gen_snapshot_exe") {
deps = [ "../runtime/bin:gen_snapshot_product" ]
src_dir =
get_label_info("../runtime/bin:gen_snapshot_product", "root_out_dir")
@@ -326,6 +338,14 @@ copy("copy_gen_snapshot") {
]
}
if (_has_dot_sym) {
copy("copy_gen_snapshot_sym") {
deps = [ "../runtime/bin:gen_snapshot_product" ]
sources = [ "$root_out_dir/gen_snapshot_product.sym" ]
outputs = [ "$root_out_dir/$dart_sdk_output/bin/utils/gen_snapshot${executable_suffix}.sym" ]
}
}
copy("copy_vm_platform_strong_product") {
visibility = [ ":group_dart2native" ]
deps = [ "../runtime/vm:vm_platform_product" ]