|
5 | 5 | import 'dart:async'; |
6 | 6 | import 'dart:ffi'; |
7 | 7 | import 'dart:io'; |
| 8 | +import 'dart:math' as math; |
8 | 9 |
|
9 | 10 | import 'package:code_assets/code_assets.dart'; |
10 | 11 | import 'package:logging/logging.dart'; |
@@ -245,47 +246,45 @@ Future<RunProcessResult?> _runDumpbin( |
245 | 246 | ); |
246 | 247 | } |
247 | 248 |
|
248 | | -Future<int> textSectionAddress(Uri dylib) async { |
| 249 | +Future<void> expectPageSize(Uri dylib, int pageSize) async { |
249 | 250 | if (Platform.isMacOS) { |
250 | 251 | // Find the line in the objdump output that looks like: |
251 | | - // 11 .text 00000046 00000000000045a0 TEXT |
| 252 | + // LOAD off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**14 |
252 | 253 | final result = await runProcess( |
253 | 254 | executable: Uri.file('objdump'), |
254 | | - arguments: ['--headers', dylib.toFilePath()], |
| 255 | + arguments: ['-p', dylib.toFilePath()], |
255 | 256 | logger: logger, |
256 | 257 | ); |
257 | 258 | expect(result.exitCode, 0); |
258 | | - final textSection = result.stdout |
| 259 | + final loadHeader = result.stdout |
259 | 260 | .split('\n') |
260 | | - .firstWhere((e) => e.contains('.text')); |
261 | | - final parsed = textSection.split(' ').where((e) => e.isNotEmpty).toList(); |
262 | | - expect(parsed[1], '.text'); |
263 | | - expect(parsed[4], 'TEXT'); |
264 | | - final vma = int.parse(parsed[3], radix: 16); |
265 | | - return vma; |
| 261 | + .firstWhere((e) => e.contains('LOAD')); |
| 262 | + final parsed = loadHeader.split(' ').where((e) => e.isNotEmpty).toList(); |
| 263 | + expect(parsed[7], 'align'); |
| 264 | + expect(parsed[8], startsWith('2**')); |
| 265 | + final alignment = math.pow(2, int.parse(parsed[8].substring('2**'.length))); |
| 266 | + expect(alignment, pageSize); |
266 | 267 | } |
267 | 268 | if (Platform.isLinux) { |
| 269 | + // The readelf output has the following structure: |
| 270 | + // Type Offset VirtAddr PhysAddr |
| 271 | + // FileSiz MemSiz Flags Align |
268 | 272 | // Find the line in the readelf output that looks like: |
269 | | - // [11] .text PROGBITS 00004328 000328 000064 00 AX 0 0 4 |
270 | | - final result = await readelf(dylib.toFilePath(), 'S'); |
271 | | - final textSection = result |
272 | | - .split('\n') |
273 | | - .firstWhere((e) => e.contains('.text')); |
274 | | - final parsed = textSection.split(' ').where((e) => e.isNotEmpty).toList(); |
275 | | - expect(parsed[1], '.text'); |
276 | | - expect(parsed[2], 'PROGBITS'); |
277 | | - final addr = int.parse(parsed[3], radix: 16); |
278 | | - return addr; |
279 | | - } |
280 | | - throw UnimplementedError(); |
281 | | -} |
282 | | - |
283 | | -Future<void> expectPageSize(Uri dylib, int pageSize) async { |
284 | | - if (Platform.isMacOS || Platform.isLinux) { |
285 | | - // If page size is 16kb, the `.text` section address should be |
286 | | - // above 0x4000. With smaller page sizes it's above 0x1000. |
287 | | - final vma = await textSectionAddress(dylib); |
288 | | - expect(vma, greaterThanOrEqualTo(pageSize)); |
| 273 | + // LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 |
| 274 | + // 0x0000000000000528 0x0000000000000528 R 0x1000 |
| 275 | + final result = await readelf(dylib.toFilePath(), 'l'); |
| 276 | + // Capture the line after the line that contains "LOAD". |
| 277 | + final regExp = RegExp('LOAD.*\n(.*)'); |
| 278 | + final loadSegment = regExp.firstMatch(result)!.group(1)!; |
| 279 | + final alignment = int.parse( |
| 280 | + loadSegment |
| 281 | + .split(' ') |
| 282 | + .where((e) => e.isNotEmpty) |
| 283 | + .last |
| 284 | + .substring('0x'.length), |
| 285 | + radix: 16, |
| 286 | + ); |
| 287 | + expect(alignment, pageSize); |
289 | 288 | } |
290 | 289 | } |
291 | 290 |
|
|
0 commit comments