LD_PRELOAD-able library to hook malloc functions.
Test: Profile trace_processor_shell on Linux.
Bug: 160399441
Change-Id: I9ceaa1ff195468f2cc77908915171613f495309e
diff --git a/Android.bp b/Android.bp
index eace06e..0f587a6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -376,6 +376,7 @@
":perfetto_src_profiling_common_unwind_support",
":perfetto_src_profiling_memory_client",
":perfetto_src_profiling_memory_client_ext",
+ ":perfetto_src_profiling_memory_client_ext_standalone",
":perfetto_src_profiling_memory_daemon",
":perfetto_src_profiling_memory_ring_buffer",
":perfetto_src_profiling_memory_scoped_spinlock",
@@ -385,7 +386,6 @@
":perfetto_src_tracing_core_core",
":perfetto_src_tracing_ipc_common",
":perfetto_src_tracing_ipc_producer_producer",
- "src/profiling/memory/client_ext_standalone.cc",
],
shared_libs: [
"liblog",
@@ -6376,6 +6376,14 @@
],
}
+// GN: //src/profiling/memory:client_ext_standalone
+filegroup {
+ name: "perfetto_src_profiling_memory_client_ext_standalone",
+ srcs: [
+ "src/profiling/memory/client_ext_standalone.cc",
+ ],
+}
+
// GN: //src/profiling/memory:daemon
filegroup {
name: "perfetto_src_profiling_memory_daemon",
diff --git a/src/profiling/memory/BUILD.gn b/src/profiling/memory/BUILD.gn
index 3a80ec5..50c9435 100644
--- a/src/profiling/memory/BUILD.gn
+++ b/src/profiling/memory/BUILD.gn
@@ -76,7 +76,7 @@
sources = [ "heapprofd_standalone_client_example.cc" ]
}
-shared_library("heapprofd_standalone_client") {
+source_set("client_ext_standalone") {
deps = [
":client_ext",
":daemon",
@@ -85,11 +85,22 @@
"../../base",
"../common:proc_utils",
]
+ sources = [ "client_ext_standalone.cc" ]
+}
+
+# This can be used to instrument custom allocators to report their allocations
+# to Perfetto. This bundles a copy of heapprofd in the library, in contrast to
+# heapprofd_client_api (see below), which expects one to be present in the
+# Android platform.
+shared_library("heapprofd_standalone_client") {
+ deps = [
+ ":client_ext_standalone",
+ "../../../gn:default_deps",
+ ]
ldflags = [
"-Wl,--version-script",
rebase_path("heapprofd_client_api.map.txt", root_build_dir),
]
- sources = [ "client_ext_standalone.cc" ]
}
shared_library("heapprofd_standalone_client_noop") {
@@ -117,6 +128,22 @@
}
}
+# On GLibc Linux, this can be used to override the allocators using
+# LD_PRELOAD. On non-GLibc, this will probably fail to link.
+shared_library("heapprofd_preload") {
+ deps = [
+ ":client_ext_standalone",
+ ":wrap_allocators",
+ "../../../gn:default_deps",
+ "../../base",
+ ]
+ ldflags = [
+ "-Wl,--version-script",
+ rebase_path("heapprofd_preload.map.txt", root_build_dir),
+ ]
+ sources = [ "malloc_preload.cc" ]
+}
+
# On Android builds, this is converted to
# header_libs: ["bionic_libc_platform_headers"].
source_set("bionic_libc_platform_headers_on_android") {
@@ -143,6 +170,10 @@
}
source_set("wrap_allocators") {
+ deps = [
+ "../../../gn:default_deps",
+ "../../base",
+ ]
sources = [ "wrap_allocators.cc" ]
}
diff --git a/src/profiling/memory/heapprofd_preload.map.txt b/src/profiling/memory/heapprofd_preload.map.txt
new file mode 100644
index 0000000..ca2ffbb
--- /dev/null
+++ b/src/profiling/memory/heapprofd_preload.map.txt
@@ -0,0 +1,15 @@
+{
+ global:
+ malloc;
+ free;
+ calloc;
+ realloc;
+ posix_memalign;
+ aligned_alloc;
+ memalign;
+ pvalloc;
+ valloc;
+ reallocarray;
+ local:
+ *;
+};
diff --git a/src/profiling/memory/malloc_preload.cc b/src/profiling/memory/malloc_preload.cc
new file mode 100644
index 0000000..7c036b4
--- /dev/null
+++ b/src/profiling/memory/malloc_preload.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <malloc.h>
+#include <unistd.h>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/profiling/memory/client_ext.h"
+#include "src/profiling/memory/wrap_allocators.h"
+
+namespace {
+// AHeapProfile_registerHeap is guaranteed to be safe to call from global
+// constructors.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wglobal-constructors"
+uint32_t g_heap_id =
+ AHeapProfile_registerHeap(AHeapInfo_create("com.android.malloc"));
+#pragma GCC diagnostic pop
+} // namespace
+
+extern "C" {
+
+// These are exported by GLibc to be used by functions overwriting malloc
+// to call back to the real implementation.
+extern void* __libc_malloc(size_t);
+extern void __libc_free(void*);
+extern void* __libc_calloc(size_t, size_t);
+extern void* __libc_realloc(void*, size_t);
+extern int __libc_posix_memalign(void**, size_t, size_t);
+extern void* __libc_memalign(size_t, size_t);
+extern void* __libc_pvalloc(size_t);
+extern void* __libc_valloc(size_t);
+extern void* __libc_reallocarray(void*, size_t, size_t);
+
+#pragma GCC visibility push(default)
+
+void* malloc(size_t size) {
+ return perfetto::profiling::wrap_malloc(g_heap_id, __libc_malloc, size);
+}
+
+void free(void* ptr) {
+ return perfetto::profiling::wrap_free(g_heap_id, __libc_free, ptr);
+}
+
+void* calloc(size_t nmemb, size_t size) {
+ return perfetto::profiling::wrap_calloc(g_heap_id, __libc_calloc, nmemb,
+ size);
+}
+
+void* realloc(void* ptr, size_t size) {
+ return perfetto::profiling::wrap_realloc(g_heap_id, __libc_realloc, ptr,
+ size);
+}
+
+int posix_memalign(void** memptr, size_t alignment, size_t size) {
+ return perfetto::profiling::wrap_posix_memalign(
+ g_heap_id, __libc_posix_memalign, memptr, alignment, size);
+}
+
+void* aligned_alloc(size_t alignment, size_t size) {
+ return perfetto::profiling::wrap_memalign(g_heap_id, __libc_memalign,
+ alignment, size);
+}
+
+void* memalign(size_t alignment, size_t size) {
+ return perfetto::profiling::wrap_memalign(g_heap_id, __libc_memalign,
+ alignment, size);
+}
+
+void* pvalloc(size_t size) {
+ return perfetto::profiling::wrap_pvalloc(g_heap_id, __libc_pvalloc, size);
+}
+
+void* valloc(size_t size) {
+ return perfetto::profiling::wrap_valloc(g_heap_id, __libc_valloc, size);
+}
+
+void* reallocarray(void* ptr, size_t nmemb, size_t size) {
+ return perfetto::profiling::wrap_reallocarray(g_heap_id, __libc_reallocarray,
+ ptr, nmemb, size);
+}
+
+#pragma GCC visibility pop
+}
diff --git a/src/profiling/memory/wrap_allocators.cc b/src/profiling/memory/wrap_allocators.cc
index bcf3b1c..f7ac4b8 100644
--- a/src/profiling/memory/wrap_allocators.cc
+++ b/src/profiling/memory/wrap_allocators.cc
@@ -120,5 +120,18 @@
return addr;
}
+void* wrap_reallocarray(uint32_t heap_id,
+ void* (*fn)(void*, size_t, size_t),
+ void* pointer,
+ size_t nmemb,
+ size_t size) {
+ if (pointer)
+ AHeapProfile_reportFree(heap_id, reinterpret_cast<uint64_t>(pointer));
+ void* addr = fn(pointer, nmemb, size);
+ AHeapProfile_reportAllocation(heap_id, reinterpret_cast<uint64_t>(addr),
+ nmemb * size);
+ return addr;
+}
+
} // namespace profiling
} // namespace perfetto
diff --git a/src/profiling/memory/wrap_allocators.h b/src/profiling/memory/wrap_allocators.h
index 8b5d420..ce9fb3e 100644
--- a/src/profiling/memory/wrap_allocators.h
+++ b/src/profiling/memory/wrap_allocators.h
@@ -45,6 +45,12 @@
void* wrap_pvalloc(uint32_t heap_id, void* (*fn)(size_t), size_t size);
void* wrap_valloc(uint32_t heap_id, void* (*fn)(size_t), size_t size);
+void* wrap_reallocarray(uint32_t heap_id,
+ void* (*fn)(void*, size_t, size_t),
+ void* pointer,
+ size_t nmemb,
+ size_t size);
+
} // namespace profiling
} // namespace perfetto