-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathpatching.gradle
More file actions
285 lines (278 loc) · 12.8 KB
/
patching.gradle
File metadata and controls
285 lines (278 loc) · 12.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/*
* Copyright 2025 Datadog, Inc
*
* 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.
*/
/**
* Unified upstream patching configuration for DataDog Java Profiler
*
* This file defines all modifications applied to async-profiler upstream source files
* to ensure compatibility with DataDog's requirements (ASan, memory safety, API extensions)
*
* CONFIGURATION SYNTAX AND SEMANTICS
* ==================================
*
* Root Structure:
* ---------------
* ext.upstreamPatches = [
* "filename1.cpp": [patches for file1],
* "filename2.h": [patches for file2]
* ]
*
* File Configuration Structure:
* ----------------------------
* Each file entry contains:
*
* "filename.ext": [
* validations: [ // Optional: Pre-patch validation rules
* [contains: "required_text"], // Ensures file contains specific text
* [contains: "another_check"] // Multiple validations run in sequence
* ],
* operations: [ // Required: List of patch operations
* [
* type: "patch_type", // Required: Type of patch operation
* name: "Human readable name", // Optional: Description of what this patch does
* description: "Detailed...", // Optional: Extended description
* find: "regex_pattern", // Required: Regex pattern to find in file
* replace: "replacement_text", // Required: Text to replace matches with
* idempotent_check: "check_text" // Optional: Text that indicates patch already applied
* ]
* ]
* ]
*
* PATCH OPERATION TYPES
* ====================
*
* 1. function_attribute:
* Purpose: Add attributes (like __attribute__) to function declarations
* Example: Add ASan no_sanitize attribute to prevent false positives
* find: "(bool\\s+StackFrame::unwindStub\\s*\\()"
* replace: "__attribute__((no_sanitize(\"address\"))) $1"
*
* 2. expression_replace:
* Purpose: Replace unsafe code patterns with safe equivalents
* Example: Replace direct pointer dereference with memcpy for ASan compatibility
* find: "\\*\\(unsigned int\\*\\)\\s*entry"
* replace: "([&] { unsigned int val; memcpy(&val, entry, sizeof(val)); return val; }())"
*
* 3. method_declaration:
* Purpose: Add new method declarations to class definitions
* Example: Add clearParsingCaches method to Symbols class
* find: "(static bool haveKernelSymbols\\(\\) \\{[^}]+\\})"
* replace: "$1\n static void clearParsingCaches();"
*
* 4. method_implementation:
* Purpose: Add complete method implementations to source files
* Example: Add clearParsingCaches implementation with cache clearing logic
* find: "(#endif \\/\\/ __linux__\\s*$)"
* replace: "void Symbols::clearParsingCaches() {\n _parsed_inodes.clear();\n}\n\n$1"
*
* REGEX PATTERNS AND REPLACEMENTS
* ===============================
*
* Pattern Syntax:
* - Use Java regex syntax (java.util.regex.Pattern)
* - Escape special characters: \\( \\) \\{ \\} \\[ \\] \\* \\+ \\? \\. \\|
* - Use \\s for whitespace, \\w for word characters, \\d for digits
* - Use capture groups: (pattern) to capture parts for reuse
* - Use non-capturing groups: (?:pattern) when grouping without capture
*
* Replacement Syntax:
* - Use $1, $2, etc. to reference capture groups from find pattern
* - Use \n for newlines in replacement text
* - Use \t for tabs (though spaces are preferred for consistency)
* - Escape dollar signs as \$ if literal $ needed
*
* IDEMPOTENT OPERATIONS
* ====================
*
* Purpose: Prevent applying same patch multiple times
* - Set idempotent_check to text that would exist after patch is applied
* - System checks for this text before applying patch
* - If found, patch is skipped with "already applied" message
* - Critical for maintaining clean, predictable builds
*
* Example:
* find: "(bool\\s+StackFrame::unwindStub\\s*\\()"
* replace: "__attribute__((no_sanitize(\"address\"))) $1"
* idempotent_check: "__attribute__((no_sanitize(\"address\"))) bool StackFrame::unwindStub("
*
* VALIDATION RULES
* ===============
*
* Purpose: Ensure upstream file structure hasn't changed in incompatible ways
* Types:
* - contains: "text" - File must contain this exact text
* - Validates that expected functions, classes, or patterns exist
* - Fails fast if upstream changes break patch assumptions
* - Helps maintain compatibility across upstream updates
*
* Best Practices:
* - Validate key function signatures that patches modify
* - Validate class names and critical code structures
* - Keep validations minimal but sufficient to catch breaking changes
*
* MAINTENANCE GUIDELINES
* =====================
*
* Adding New Patches:
* 1. Add file entry if not exists: "newfile.cpp": [...]
* 2. Add validations to verify expected code structure
* 3. Add operation with appropriate type, find, replace
* 4. Always include idempotent_check to prevent double-application
* 5. Test thoroughly with clean upstream files
*
* Modifying Existing Patches:
* 1. Update find pattern if upstream code changed
* 2. Update replace text if modification requirements changed
* 3. Update idempotent_check to match new replacement
* 4. Update validations if structural assumptions changed
*
* Removing Patches:
* 1. Remove entire operation block
* 2. Remove validations that are no longer needed
* 3. Remove file entry if no operations remain
* 4. Clean up any orphaned files that depended on removed patches
*/
ext.upstreamPatches = [
// Stack frame unwinding patches for ASan compatibility and memory safety
"stackFrame_x64.cpp": [
validations: [
[contains: "StackFrame::"],
[contains: "StackFrame::unwindStub"],
[contains: "StackFrame::checkInterruptedSyscall"]
],
operations: [
[
type: "function_attribute",
name: "Add ASan no_sanitize attribute to unwindStub",
description: "Adds __attribute__((no_sanitize(\"address\"))) to unwindStub function to prevent ASan false positives during stack unwinding",
find: "(bool\\s+StackFrame::unwindStub\\s*\\()",
replace: "__attribute__((no_sanitize(\"address\"))) \$1",
idempotent_check: "__attribute__((no_sanitize(\"address\"))) bool StackFrame::unwindStub("
],
[
type: "expression_replace",
name: "Safe memory access for entry pointer check",
description: "Replaces unsafe pointer dereference with safe memcpy-based access to prevent ASan violations",
find: "entry\\s*!=\\s*NULL\\s*&&\\s*\\*\\(unsigned int\\*\\)\\s*entry\\s*==\\s*0xec8b4855",
replace: "entry != NULL && ([&] { unsigned int val; memcpy(&val, entry, sizeof(val)); return val; }()) == 0xec8b4855"
],
[
type: "function_attribute",
name: "Add ASan no_sanitize attribute to checkInterruptedSyscall",
description: "Adds __attribute__((no_sanitize(\"address\"))) to checkInterruptedSyscall function",
find: "(bool\\s+StackFrame::checkInterruptedSyscall\\s*\\()",
replace: "__attribute__((no_sanitize(\"address\"))) \$1",
idempotent_check: "__attribute__((no_sanitize(\"address\"))) bool StackFrame::checkInterruptedSyscall("
],
[
type: "expression_replace",
name: "Safe memory access for pc offset read",
description: "Replaces unsafe pointer dereference at pc-6 with safe memcpy-based access",
find: "\\*\\(int\\*\\)\\s*\\(pc\\s*-\\s*6\\)",
replace: "([&] { int val; memcpy(&val, (const void*)(pc - 6), sizeof(val)); return val; }())"
]
]
],
// Stack walker patches for ASan compatibility
"stackWalker.cpp": [
validations: [[contains: "StackWalker::"], [contains: "StackWalker::walkVM"]],
operations: [
[
type: "function_attribute",
name: "Add ASan no_sanitize attribute to walkVM",
description: "Adds __attribute__((no_sanitize(\"address\"))) to walkVM function to prevent ASan false positives during VM stack walking",
find: "(int\\s+StackWalker::walkVM\\s*\\()",
replace: "__attribute__((no_sanitize(\"address\"))) \$1",
idempotent_check: "__attribute__((no_sanitize(\"address\"))) int StackWalker::walkVM("
]
]
],
// Symbol management patches for DataDog-specific API extensions
"symbols.h": [
validations: [[contains: "class Symbols"], [contains: "static bool haveKernelSymbols"]],
operations: [
[
type: "method_declaration",
name: "Add clearParsingCaches method declaration",
description: "Adds clearParsingCaches static method declaration to Symbols class for test compatibility",
find: "(static bool haveKernelSymbols\\(\\) \\{[^}]+\\})",
replace: "\$1\n // Clear internal caches - mainly for test purposes\n static void clearParsingCaches();",
idempotent_check: "static void clearParsingCaches();"
]
]
],
// Symbol implementation patches for DataDog-specific API extensions
"symbols_linux.cpp": [
validations: [[contains: "#ifdef __linux__"], [contains: "_parsed_inodes"], [contains: "loadSymbolTable"]],
operations: [
[
type: "expression_replace",
name: "Fix pointer overflow in loadSymbolTable",
description: "Replace unsafe pointer arithmetic with overflow-safe version to prevent ASAN failures while preserving original semantics",
find: "const char\\* addr = base != NULL \\? base \\+ sym->st_value : \\(const char\\*\\)sym->st_value;",
replace: "// Use safe pointer arithmetic to avoid ASAN overflow while preserving original NULL base semantics\n const char* addr = base != NULL ? (const char*)((uintptr_t)base + (uintptr_t)sym->st_value) : (const char*)sym->st_value;",
idempotent_check: "// Use safe pointer arithmetic to avoid ASAN overflow while preserving original NULL base semantics"
],
[
type: "method_implementation",
name: "Add clearParsingCaches method implementation",
description: "Adds clearParsingCaches static method implementation that clears internal parsing caches",
find: "(#endif \\/\\/ __linux__\\s*\$)",
replace: "// Implementation of clearParsingCaches for test compatibility\nvoid Symbols::clearParsingCaches() {\n _parsed_inodes.clear();\n}\n\n\$1",
idempotent_check: "void Symbols::clearParsingCaches()"
]
]
],
// Symbol implementation patches for macOS (DataDog-specific API extensions and ASan compatibility)
"symbols_macos.cpp": [
validations: [[contains: "#ifdef __APPLE__"], [contains: "loadSymbols"], [contains: "n_value"]],
operations: [
[
type: "expression_replace",
name: "Fix pointer overflow in loadSymbols for macOS",
description: "Replace unsafe pointer arithmetic with overflow-safe version to prevent ASAN failures on macOS",
find: "const char\\* addr = _vmaddr_slide \\+ sym->n_value;",
replace: "// Use safer arithmetic to avoid ASAN overflow while preserving all symbols\n const char* addr = (const char*)((uintptr_t)_vmaddr_slide + (uintptr_t)sym->n_value);",
idempotent_check: "// Use safer arithmetic to avoid ASAN overflow while preserving all symbols"
]
]
],
// Stack frame header patches for DataDog-specific API extensions
"stackFrame.h": [
validations: [
[contains: "class StackFrame"],
[contains: "unwindStub"],
[contains: "adjustSP"]
],
operations: [
[
type: "expression_replace",
name: "Make StackFrame constructor explicit",
description: "Add explicit keyword to prevent implicit conversions",
find: "StackFrame\\(void\\* ucontext\\)",
replace: "explicit StackFrame(void* ucontext)",
idempotent_check: "explicit StackFrame(void* ucontext)"
],
[
type: "method_declaration",
name: "Add DataDog SP baseline helper methods",
description: "Add sender_sp_baseline, read_caller_pc_from_sp, and read_saved_fp_from_sp methods for DataDog unwinding logic",
find: "(void adjustSP\\(const void\\* entry, const void\\* pc, uintptr_t& sp\\);)",
replace: "\$1\n\n // SP baseline helpers for compiled frame unwinding\n uintptr_t sender_sp_baseline(const NMethod* nm, uintptr_t sp, uintptr_t fp, const void* pc);\n const void* read_caller_pc_from_sp(uintptr_t sp_base);\n uintptr_t read_saved_fp_from_sp(uintptr_t sp_base);",
idempotent_check: "uintptr_t sender_sp_baseline("
]
]
]
]