-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[swift-inspect] implement Android support including remote heap iteration #78275
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
f981f35
[swift-inspect] full Android implementation including heap iteration
andrurogerz e90f5c5
[swift-inspect] refactor heap iteration
andrurogerz 43c9623
[swift-inspect] misc cleanup
andrurogerz d7e8c74
[swift-inspect] add ptrace retries
andrurogerz 21ea119
[swift-inspect] fix Android README.md
andrurogerz 714ce52
[swift-inspect] indent RegisterSet.swift
andrurogerz 25da1a9
[swift-inspect] use malloc_disable/malloc_enable when iterating the heap
andrurogerz ac3fec1
[swift-inspect] move Android-specific memory region naming to Android
andrurogerz 0a436ba
[swift-inspect] minor cleanup
andrurogerz 03dae5d
[swift-inspect] minor cleanup and documentation
andrurogerz c0257d8
add missing copyright header to RegisterSet.swift
andrurogerz 9fdd46f
refactor remote function calls to their own methods
andrurogerz 7b10cc8
PR feedback: README.md updates
andrurogerz 48d6237
PR Feedback: use __builtin_debugtrap and safe function size calculation
andrurogerz 5488f2f
PR Feedback: improve PTrace implementation
andrurogerz 9604994
PR Feedback: make PTrace a non-copyable struct
andrurogerz 5cc83cc
Merge branch 'main' into swift-inspect-android
andrurogerz 61cb0c3
PR Feedback
andrurogerz 0ca4971
Merge branch 'swift-inspect-android' of github.com:andrurogerz/swift …
andrurogerz 21d139d
missed a __volatile__
andrurogerz 5dd761a
force 8-byte alignment on heap_iterate_callback_end
andrurogerz b997bdb
Define a new text section and use a linker script to safely calculat…
andrurogerz a4a7384
add CMake build support for Android
andrurogerz e6dc459
remove custom linker script in favor of implicit section maker symbols
andrurogerz 4a9087c
update Android build command in README.md for newst Swift Android SDK
andrurogerz 6381de4
PR feedback: fix incorrect comment
andrurogerz f2649f2
PR Feedback: make PTrace.init fileprivate
andrurogerz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 2024 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include <string.h> | ||
|
||
#include "heap.h" | ||
|
||
/* The heap metadata buffer is interpreted as an array of 8-byte pairs. The | ||
* first pair contains metadata describing the buffer itself: max valid index | ||
* (e.g. size of the buffer) and next index (e.g. write cursor/position). Each | ||
* subsequent pair describes the address and length of a heap entry in the | ||
* remote process. A 4KiB page provides sufficient space for the header and | ||
* 255 (address, length) pairs. | ||
* | ||
* ------------ | ||
* | uint64_t | max valid index (e.g. sizeof(buffer) / sizeof(uint64_t)) | ||
* ------------ | ||
* | uint64_t | next free index (starts at 2) | ||
* ------------ | ||
* | uint64_t | heap item 1 address | ||
* ------------ | ||
* | uint64_t | heap item 1 size | ||
* ------------ | ||
* | uint64_t | heap item 2 address | ||
* ------------ | ||
* | uint64_t | heap item 2 size | ||
* ------------ | ||
* | uint64_t | ... | ||
* ------------ | ||
* | uint64_t | ... | ||
* ------------ | ||
* | uint64_t | heap item N address | ||
* ------------ | ||
* | uint64_t | heap item N size | ||
* ------------ | ||
*/ | ||
|
||
#if !__has_builtin(__builtin_debugtrap) | ||
#error("compiler support for __builtin_debugtrap is required") | ||
#endif | ||
|
||
#define MAX_VALID_IDX 0 | ||
#define NEXT_FREE_IDX 1 | ||
#define HEADER_SIZE 2 | ||
#define ENTRY_SIZE 2 | ||
|
||
// Callback for malloc_iterate. Because this function is meant to be copied to | ||
// a different process for execution, it must not make any function calls to | ||
// ensure compiles to simple, position-independent code. It is implemented in C | ||
// for readability/maintainability. It is placed in its own code section to | ||
// simplify calculating its size. | ||
__attribute__((noinline, used, section("heap_iterator"))) | ||
static void heap_iterate_callback(unsigned long base, unsigned long size, void *arg) { | ||
volatile uint64_t *data = (uint64_t*)arg; | ||
while (data[NEXT_FREE_IDX] >= data[MAX_VALID_IDX]) { | ||
// SIGTRAP indicates the buffer is full and needs to be drained before more | ||
// entries can be written. | ||
__builtin_debugtrap(); | ||
|
||
// After the SIGTRAP, the signal handler advances the instruction pointer | ||
// (PC) to the next instruction. Inserting a nop instruction here ensures | ||
// the CPU has a clear, executable instruction to process, which avoids | ||
// potential speculative execution or pipeline issues that could arise if | ||
// the next instruction were a control transfer like a branch or jump. | ||
__asm__ __volatile__("nop"); | ||
} | ||
data[data[NEXT_FREE_IDX]++] = base; | ||
data[data[NEXT_FREE_IDX]++] = size; | ||
} | ||
|
||
// The linker implicitly defines __start- and __stop- prefixed symbols that mark | ||
// the start and end of user defined sections. | ||
extern char __stop_heap_iterator[]; | ||
|
||
void* heap_iterate_callback_start() { | ||
return (void*)heap_iterate_callback; | ||
} | ||
|
||
size_t heap_iterate_callback_len() { | ||
return (uintptr_t)__stop_heap_iterator - (uintptr_t)heap_iterate_callback; | ||
} | ||
|
||
bool heap_iterate_metadata_init(void* data, size_t len) { | ||
uint64_t *metadata = data; | ||
const uint64_t max_entries = len / sizeof(uint64_t); | ||
if (max_entries < HEADER_SIZE + ENTRY_SIZE) | ||
return false; | ||
|
||
memset(data, 0, len); | ||
metadata[MAX_VALID_IDX] = max_entries; | ||
metadata[NEXT_FREE_IDX] = HEADER_SIZE; | ||
return true; | ||
} | ||
|
||
bool heap_iterate_metadata_process( | ||
void* data, size_t len, void* callback_context, heap_iterate_entry_callback_t callback) { | ||
uint64_t *metadata = data; | ||
const uint64_t max_entries = len / sizeof(uint64_t); | ||
const uint64_t end_index = metadata[NEXT_FREE_IDX]; | ||
|
||
if (metadata[MAX_VALID_IDX] != max_entries || end_index > max_entries) | ||
return false; | ||
|
||
for (size_t i = HEADER_SIZE; i < end_index; i += ENTRY_SIZE) { | ||
const uint64_t base = metadata[i]; | ||
const uint64_t size = metadata[i + 1]; | ||
callback(callback_context, base, size); | ||
} | ||
|
||
return true; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 2024 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#pragma once | ||
|
||
#include <stdbool.h> | ||
#include <stdint.h> | ||
|
||
#if defined(__cplusplus) | ||
extern "C" { | ||
#endif | ||
|
||
// Location of the heap_iterate callback. | ||
void* heap_iterate_callback_start(); | ||
|
||
// Size of the heap_iterate callback. | ||
size_t heap_iterate_callback_len(); | ||
|
||
// Initialize the provided buffer to receive heap iteration metadata. | ||
bool heap_iterate_metadata_init(void* data, size_t len); | ||
|
||
// Callback invoked by heap_iterate_data_process for each heap entry . | ||
typedef void (*heap_iterate_entry_callback_t)(void* context, uint64_t base, uint64_t len); | ||
|
||
// Process all heap iteration entries in the provided buffer. | ||
bool heap_iterate_metadata_process( | ||
void* data, size_t len, void* callback_context, heap_iterate_entry_callback_t callback); | ||
|
||
#if defined(__cplusplus) | ||
} | ||
#endif |
4 changes: 4 additions & 0 deletions
4
tools/swift-inspect/Sources/AndroidCLib/include/module.modulemap
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
module AndroidCLib { | ||
header "heap.h" | ||
export * | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.