[llvm] 0712038 - [CSSPGO][llvm-profgen] Allow multiple executable load segments.

Hongtao Yu via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 13 18:22:50 PDT 2021


Author: Hongtao Yu
Date: 2021-07-13T18:22:24-07:00
New Revision: 071203845887a2ff0347747bd5864f8738d17eef

URL: https://github.com/llvm/llvm-project/commit/071203845887a2ff0347747bd5864f8738d17eef
DIFF: https://github.com/llvm/llvm-project/commit/071203845887a2ff0347747bd5864f8738d17eef.diff

LOG: [CSSPGO][llvm-profgen] Allow multiple executable load segments.

The linker or post-link optimizer can create an ELF image with multiple executable segments each of which will be loaded separately at run time. This breaks the assumption of llvm-profgen that currently only supports one base load address. What it ends up with is that the subsequent mmap events will be treated as an overwrite of the first mmap event which will in turn screw up address mapping. While it is non-trivial to support multiple separate load addresses and given that on x64 those segments will always be loaded at consecutive addresses (though via separate mmap
sys calls), I'm adding an error checking logic to bail out if that's violated and keep using a single load address which is the address of the first executable segment.

Also changing the disassembly output from printing section offset to printing the virtual address instead, which matches the behavior of objdump.

Differential Revision: https://reviews.llvm.org/D103178

Added: 
    llvm/test/tools/llvm-profgen/Inputs/multi-load-segs.perfbin
    llvm/test/tools/llvm-profgen/Inputs/multi-load-segs.perfscript
    llvm/test/tools/llvm-profgen/Inputs/symbolize.ll
    llvm/test/tools/llvm-profgen/Inputs/symbolize.perfbin
    llvm/test/tools/llvm-profgen/disassemble.test
    llvm/test/tools/llvm-profgen/multi-load-segs.test
    llvm/test/tools/llvm-profgen/symbolize.test

Modified: 
    llvm/test/tools/llvm-profgen/mmapEvent.test
    llvm/tools/llvm-profgen/PerfReader.cpp
    llvm/tools/llvm-profgen/PerfReader.h
    llvm/tools/llvm-profgen/ProfiledBinary.cpp
    llvm/tools/llvm-profgen/ProfiledBinary.h

Removed: 
    llvm/test/tools/llvm-profgen/disassemble.s
    llvm/test/tools/llvm-profgen/symbolize.ll


################################################################################
diff  --git a/llvm/test/tools/llvm-profgen/Inputs/multi-load-segs.perfbin b/llvm/test/tools/llvm-profgen/Inputs/multi-load-segs.perfbin
new file mode 100755
index 000000000000..68438baa63f0
Binary files /dev/null and b/llvm/test/tools/llvm-profgen/Inputs/multi-load-segs.perfbin 
diff er

diff  --git a/llvm/test/tools/llvm-profgen/Inputs/multi-load-segs.perfscript b/llvm/test/tools/llvm-profgen/Inputs/multi-load-segs.perfscript
new file mode 100644
index 000000000000..d8fda04d837a
--- /dev/null
+++ b/llvm/test/tools/llvm-profgen/Inputs/multi-load-segs.perfscript
@@ -0,0 +1,10 @@
+PERF_RECORD_MMAP2 3476378/3476378: [0x201000(0x1000) @ 0 00:23 51215901 72455]: r-xp multi-load-segs.perfbin
+PERF_RECORD_MMAP2 3476378/3476378: [0x202000(0x1000) @ 0x1000 00:23 51215901 72455]: r-xp multi-load-segs.perfbin
+PERF_RECORD_MMAP2 3476378/3476378: [0x400000(0x1000) @ 0x200000 00:23 51215901 72455]: r-xp multi-load-segs.perfbin
+
+	          201a1e
+	    7f9f03a46d95
+	          20178a
+ 0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/5  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/5  0x201a56/0x201a10/P/-/-/5  0x201a56/0x201a10/P/-/-/5  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/3  0x201a56/0x201a10/P/-/-/7  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/3  0x201a56/0x201a10/P/-/-/6  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/3  0x201a56/0x201a10/P/-/-/6  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/4  0x201a56/0x201a10/P/-/-/3  0x201a56/0x201a10/P/-/-/6 
+
+	       
\ No newline at end of file

diff  --git a/llvm/test/tools/llvm-profgen/symbolize.ll b/llvm/test/tools/llvm-profgen/Inputs/symbolize.ll
similarity index 65%
rename from llvm/test/tools/llvm-profgen/symbolize.ll
rename to llvm/test/tools/llvm-profgen/Inputs/symbolize.ll
index 1c05e0589282..9c547379b02c 100644
--- a/llvm/test/tools/llvm-profgen/symbolize.ll
+++ b/llvm/test/tools/llvm-profgen/Inputs/symbolize.ll
@@ -1,45 +1,3 @@
-; REQUIRES: x86-registered-target
-; RUN: llc -filetype=obj %s -o %t
-; RUN: llvm-profgen --binary=%t --perfscript=%s --output=%t1 --show-disassembly-only -x86-asm-syntax=intel --show-source-locations | FileCheck %s --match-full-lines
-; RUN: llvm-profgen --binary=%t --perfscript=%s --output=%t2 --show-disassembly-only -x86-asm-syntax=intel --show-source-locations --show-canonical-fname | FileCheck %s --match-full-lines  --check-prefix=CHECK-CANO
-
-; CHECK: Disassembly of section .text [0x0, 0x4a]:
-; CHECK: <funcA.llvm.1000>:
-; CHECK:        0:	mov	eax, edi                         funcA.llvm.1000:0
-; CHECK:        2:	mov	ecx, dword ptr [rip]             funcLeaf:2 @ funcA.llvm.1000:1
-; CHECK:        8:	lea	edx, [rcx + 3]                   fib:2 @ funcLeaf:2 @ funcA.llvm.1000:1
-; CHECK:        b:	cmp	ecx, 3                           fib:2 @ funcLeaf:2 @ funcA.llvm.1000:1
-; CHECK:        e:	cmovl	edx, ecx                       fib:2 @ funcLeaf:2 @ funcA.llvm.1000:1
-; CHECK:       11:	sub	eax, edx                         funcLeaf:2 @ funcA.llvm.1000:1
-; CHECK:       13:	ret                                  funcA.llvm.1000:2
-; CHECK:       14:	nop	word ptr cs:[rax + rax]
-; CHECK:       1e:	nop
-; CHECK-CANO: <funcA>:
-; CHECK-CANO:        0:	mov	eax, edi                         funcA:0
-; CHECK-CANO:        2:	mov	ecx, dword ptr [rip]             funcLeaf:2 @ funcA:1
-; CHECK-CANO:        8:	lea	edx, [rcx + 3]                   fib:2 @ funcLeaf:2 @ funcA:1
-; CHECK-CANO:        b:	cmp	ecx, 3                           fib:2 @ funcLeaf:2 @ funcA:1
-; CHECK-CANO:        e:	cmovl	edx, ecx                       fib:2 @ funcLeaf:2 @ funcA:1
-; CHECK-CANO:       11:	sub	eax, edx                         funcLeaf:2 @ funcA:1
-; CHECK-CANO:       13:	ret                                  funcA:2
-; CHECK-CANO:       14:	nop	word ptr cs:[rax + rax]
-; CHECK-CANO:       1e:	nop
-; CHECK: <funcLeaf>:
-; CHECK:      20:	mov	eax, edi                           funcLeaf:1
-; CHECK:      22:	mov	ecx, dword ptr [rip]               funcLeaf:2
-; CHECK:      28:	lea	edx, [rcx + 3]                     fib:2 @ funcLeaf:2
-; CHECK:      2b:	cmp	ecx, 3                             fib:2 @ funcLeaf:2
-; CHECK:      2e:	cmovl	edx, ecx                         fib:2 @ funcLeaf:2
-; CHECK:      31:	sub	eax, edx                           funcLeaf:2
-; CHECK:      33:	ret                                    funcLeaf:3
-; CHECK:      34:	nop	word ptr cs:[rax + rax]
-; CHECK:      3e:	nop
-; CHECK: <fib>:
-; CHECK:      40:	lea	eax, [rdi + 3]                     fib:2
-; CHECK:      43:	cmp	edi, 3                             fib:2
-; CHECK:      46:	cmovl	eax, edi                         fib:2
-; CHECK:      49:	ret                                    fib:8
-
 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-unknown-linux-gnu"
 

diff  --git a/llvm/test/tools/llvm-profgen/Inputs/symbolize.perfbin b/llvm/test/tools/llvm-profgen/Inputs/symbolize.perfbin
new file mode 100755
index 000000000000..259cf08b90d3
Binary files /dev/null and b/llvm/test/tools/llvm-profgen/Inputs/symbolize.perfbin 
diff er

diff  --git a/llvm/test/tools/llvm-profgen/disassemble.s b/llvm/test/tools/llvm-profgen/disassemble.s
deleted file mode 100644
index be03b5a6892b..000000000000
--- a/llvm/test/tools/llvm-profgen/disassemble.s
+++ /dev/null
@@ -1,121 +0,0 @@
-# REQUIRES: x86-registered-target
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t
-# RUN: llvm-profgen --binary=%t --perfscript=%s --output=%t1 -show-disassembly-only -x86-asm-syntax=intel | FileCheck %s --match-full-lines
-
-# CHECK: Disassembly of section .text [0x0, 0x66]:
-# CHECK: <foo1>:
-# CHECK:        0:	push	rbp
-# CHECK:        1:	mov	rbp, rsp
-# CHECK:        4:	sub	rsp, 16
-# CHECK:        8:	mov	dword ptr [rbp - 4], 0
-# CHECK:        f:	mov	edi, 1
-# CHECK:       14:	call	0x19
-# CHECK:       19:	mov	edi, 2
-# CHECK:       1e:	mov	dword ptr [rbp - 8], eax
-# CHECK:       21:	call	0x26
-# CHECK:       26:	mov	ecx, dword ptr [rbp - 8]
-# CHECK:       29:	add	ecx, eax
-# CHECK:       2b:	mov	eax, ecx
-# CHECK:       2d:	add	rsp, 16
-# CHECK:       31:	pop	rbp
-# CHECK:       32:	ret
-
-# CHECK: <foo2>:
-# CHECK:       33:	push	rbp
-# CHECK:       34:	mov	rbp, rsp
-# CHECK:       37:	sub	rsp, 16
-# CHECK:       3b:	mov	dword ptr [rbp - 4], 0
-# CHECK:       42:	mov	edi, 1
-# CHECK:       47:	call	0x4c
-# CHECK:       4c:	mov	edi, 2
-# CHECK:       51:	mov	dword ptr [rbp - 8], eax
-# CHECK:       54:	call	0x59
-# CHECK:       59:	mov	ecx, dword ptr [rbp - 8]
-# CHECK:       5c:	add	ecx, eax
-# CHECK:       5e:	mov	eax, ecx
-# CHECK:       60:	add	rsp, 16
-# CHECK:       64:	pop	rbp
-# CHECK:       65:	ret
-
-
-
-.section .text
-foo1:
-	pushq	%rbp
-	movq	%rsp, %rbp
-	subq	$16, %rsp
-	movl	$0, -4(%rbp)
-	movl	$1, %edi
-	callq	_Z5funcAi
-	movl	$2, %edi
-	movl	%eax, -8(%rbp)
-	callq	_Z5funcBi
-	movl	-8(%rbp), %ecx
-	addl	%eax, %ecx
-	movl	%ecx, %eax
-	addq	$16, %rsp
-	popq	%rbp
-	retq
-
-.section .text
-foo2:
-	pushq	%rbp
-	movq	%rsp, %rbp
-	subq	$16, %rsp
-	movl	$0, -4(%rbp)
-	movl	$1, %edi
-	callq	_Z5funcBi
-	movl	$2, %edi
-	movl	%eax, -8(%rbp)
-	callq	_Z5funcAi
-	movl	-8(%rbp), %ecx
-	addl	%eax, %ecx
-	movl	%ecx, %eax
-	addq	$16, %rsp
-	popq	%rbp
-	retq
-
-# CHECK: Disassembly of section .text.hot [0x0, 0x12]:
-# CHECK: <bar>:
-# CHECK:        0:	push	rbp
-# CHECK:        1:	mov	rbp, rsp
-# CHECK:        4:	mov	dword ptr [rbp - 4], edi
-# CHECK:        7:	mov	dword ptr [rbp - 8], esi
-# CHECK:        a:	mov	eax, dword ptr [rbp - 4]
-# CHECK:        d:	add	eax, dword ptr [rbp - 8]
-# CHECK:       10:	pop	rbp
-# CHECK:       11:	ret
-
-.section .text.hot
-bar:
-	pushq	%rbp
-	movq	%rsp, %rbp
-	movl	%edi, -4(%rbp)
-	movl	%esi, -8(%rbp)
-	movl	-4(%rbp), %eax
-	addl	-8(%rbp), %eax
-	popq	%rbp
-	retq
-
-
-# CHECK: Disassembly of section .text.unlikely [0x0, 0x12]:
-# CHECK: <baz>:
-# CHECK:        0:	push	rbp
-# CHECK:        1:	mov	rbp, rsp
-# CHECK:        4:	mov	dword ptr [rbp - 4], edi
-# CHECK:        7:	mov	dword ptr [rbp - 8], esi
-# CHECK:        a:	mov	eax, dword ptr [rbp - 4]
-# CHECK:        d:	sub	eax, dword ptr [rbp - 8]
-# CHECK:       10:	pop	rbp
-# CHECK:       11:	ret
-
-.section .text.unlikely
-baz:
-	pushq	%rbp
-	movq	%rsp, %rbp
-	movl	%edi, -4(%rbp)
-	movl	%esi, -8(%rbp)
-	movl	-4(%rbp), %eax
-	subl	-8(%rbp), %eax
-	popq	%rbp
-	retq

diff  --git a/llvm/test/tools/llvm-profgen/disassemble.test b/llvm/test/tools/llvm-profgen/disassemble.test
new file mode 100644
index 000000000000..d84614a682d5
--- /dev/null
+++ b/llvm/test/tools/llvm-profgen/disassemble.test
@@ -0,0 +1,49 @@
+; RUN: llvm-profgen --perfscript=%s  --binary=%S/Inputs/inline-cs-pseudoprobe.perfbin --output=%t --show-disassembly-only | FileCheck %s
+
+; CHECK:      <bar>:
+; CHECK-NEXT:   201750:	pushq	%rbp
+; CHECK-NEXT:   201751:	movq	%rsp, %rbp
+; CHECK-NEXT:   201754:	imull	$2863311531, %edi, %eax
+; CHECK-NEXT:   20175a:	addl	$715827882, %eax
+; CHECK-NEXT:   20175f:	movl	%esi, %ecx
+; CHECK-NEXT:   201761:	negl	%ecx
+; CHECK-NEXT:   201763:	cmpl	$1431655765, %eax
+; CHECK-NEXT:   201768:	cmovbl	%esi, %ecx
+; CHECK-NEXT:   20176b:	leal	(%rcx,%rdi), %eax
+; CHECK-NEXT:   20176e:	popq	%rbp
+; CHECK-NEXT:   20176f:	retq
+
+; CHECK:      <foo>:
+; CHECK-NEXT  201770:	movl	$1, %ecx
+; CHECK-NEXT  201775:	movl	$2863311531, %r8d
+; CHECK-NEXT  20177b:	jmp	0x78e
+; CHECK-NEXT  20177d:	nopl	(%rax)
+; CHECK-NEXT  201780:	addl	$30, %esi
+; CHECK-NEXT  201783:	addl	$1, %ecx
+; CHECK-NEXT  201786:	cmpl	$16000001, %ecx
+  
+
+; clang -O3 -fexperimental-new-pass-manager -fuse-ld=lld -fpseudo-probe-for-profiling
+; -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -Xclang -mdisable-tail-calls
+; -g test.c  -o a.out
+
+#include <stdio.h>
+
+int bar(int x, int y) {
+  if (x % 3) {
+    return x - y;
+  }
+  return x + y;
+}
+
+void foo() {
+  int s, i = 0;
+  while (i++ < 4000 * 4000)
+    if (i % 91) s = bar(i, s); else s += 30;
+  printf("sum is %d\n", s);
+}
+
+int main() {
+  foo();
+  return 0;
+}

diff  --git a/llvm/test/tools/llvm-profgen/mmapEvent.test b/llvm/test/tools/llvm-profgen/mmapEvent.test
index 875bc5ca48c0..840736dac7da 100644
--- a/llvm/test/tools/llvm-profgen/mmapEvent.test
+++ b/llvm/test/tools/llvm-profgen/mmapEvent.test
@@ -1,6 +1,5 @@
 ; REQUIRES: x86-registered-target
-; RUN: llvm-mc -filetype=obj -triple=x86_64 %S/disassemble.s -o %t
-; RUN: llvm-profgen --perfscript=%s --binary=%t --output=%t --show-mmap-events | FileCheck %s
+; RUN: llvm-profgen --perfscript=%s --binary=%S/Inputs/inline-cs-pseudoprobe.perfbin --output=%t --show-mmap-events | FileCheck %s
 
 PERF_RECORD_MMAP2 2580483/2580483: [0x400000(0x1000) @ 0 103:01 539973862 1972407324]: r-xp /home/a.out
 PERF_RECORD_MMAP2 2580483/2580483: [0x7f2505b40000(0x224000) @ 0 08:04 19532214 4169021329]: r-xp /usr/lib64/ld-2.17.so

diff  --git a/llvm/test/tools/llvm-profgen/multi-load-segs.test b/llvm/test/tools/llvm-profgen/multi-load-segs.test
new file mode 100644
index 000000000000..866d1a200652
--- /dev/null
+++ b/llvm/test/tools/llvm-profgen/multi-load-segs.test
@@ -0,0 +1,17 @@
+; RUN: llvm-profgen --perfscript=%S/Inputs/multi-load-segs.perfscript --binary=%S/Inputs/multi-load-segs.perfbin --output=%t --format=text
+; RUN: FileCheck %s --input-file %t
+
+;;  %S/Inputs/multi-load-segs.perfbin is an ELF image with two executable load segments. 
+; running llvm-readelf -l %S/Inputs/multi-load-segs.perfbin gives:
+;;  LOAD           0x000000 0x0000000000200000 0x0000000000200000 0x00075c 0x00075c R   0x1000
+;;  LOAD           0x000760 0x0000000000201760 0x0000000000201760 0x0004c0 0x0004c0 R E 0x1000
+;;  LOAD           0x000c20 0x0000000000202c20 0x0000000000202c20 0x0001f0 0x0001f0 RW  0x1000
+;;  LOAD           0x000e10 0x0000000000203e10 0x0000000000203e10 0x000040 0x000058 RW  0x1000
+;;  LOAD           0x200000 0x0000000000400000 0x0000000000400000 0x0005e8 0x0005e8 R E 0x200000
+
+; CHECK:      [main:2 @ _Z10sort_arrayv:6 @ _Z11bubble_sortPii]:465:0
+; CHECK-NEXT:  4: 31
+; CHECK-NEXT:  5: 31
+; CHECK-NEXT:  7: 31
+; CHECK-NEXT:  8: 31
+; CHECK-NEXT:    !Attributes: 1

diff  --git a/llvm/test/tools/llvm-profgen/symbolize.test b/llvm/test/tools/llvm-profgen/symbolize.test
new file mode 100644
index 000000000000..8ee364d62140
--- /dev/null
+++ b/llvm/test/tools/llvm-profgen/symbolize.test
@@ -0,0 +1,41 @@
+; REQUIRES: x86-registered-target
+; RUN: llvm-profgen --binary=%S/Inputs/symbolize.perfbin --perfscript=%s --output=%t1 --show-disassembly-only -x86-asm-syntax=intel --show-source-locations | FileCheck %s --match-full-lines
+; RUN: llvm-profgen --binary=%S/Inputs/symbolize.perfbin --perfscript=%s --output=%t2 --show-disassembly-only -x86-asm-syntax=intel --show-source-locations --show-canonical-fname | FileCheck %s --match-full-lines  --check-prefix=CHECK-CANO
+
+; CHECK: Disassembly of section .text [0x520, 0x62c]:
+; CHECK:        <funcA.llvm.1000>:
+; CHECK-NEXT:     5e0:	mov	eax, edi                           funcA.llvm.1000:0
+; CHECK-NEXT:     5e2:	mov	edx, dword ptr [rip + 2099768]     funcLeaf:2 @ funcA.llvm.1000:1
+; CHECK-NEXT:     5e8:	mov	ecx, edx                           fib:2 @ funcLeaf:2 @ funcA.llvm.1000:1
+; CHECK-NEXT:     5ea:	add	ecx, 3                             fib:2 @ funcLeaf:2 @ funcA.llvm.1000:1
+; CHECK-NEXT:     5ed:	cmp	edx, 3                             fib:2 @ funcLeaf:2 @ funcA.llvm.1000:1
+; CHECK-NEXT:     5f0:	cmovl	ecx, edx                         fib:2 @ funcLeaf:2 @ funcA.llvm.1000:1
+; CHECK-NEXT:     5f3:	sub	eax, ecx                           funcLeaf:2 @ funcA.llvm.1000:1
+; CHECK-NEXT:     5f5:	ret                                    funcA.llvm.1000:2
+; CHECK-CANO:        <funcA>:
+; CHECK-CANO-NEXT:     5e0:	mov	eax, edi                           funcA:0
+; CHECK-CANO-NEXT:     5e2:	mov	edx, dword ptr [rip + 2099768]     funcLeaf:2 @ funcA:1
+; CHECK-CANO-NEXT:     5e8:	mov	ecx, edx                           fib:2 @ funcLeaf:2 @ funcA:1
+; CHECK-CANO-NEXT:     5ea:	add	ecx, 3                             fib:2 @ funcLeaf:2 @ funcA:1
+; CHECK-CANO-NEXT:     5ed:	cmp	edx, 3                             fib:2 @ funcLeaf:2 @ funcA:1
+; CHECK-CANO-NEXT:     5f0:	cmovl	ecx, edx                         fib:2 @ funcLeaf:2 @ funcA:1
+; CHECK-CANO-NEXT:     5f3:	sub	eax, ecx                           funcLeaf:2 @ funcA:1
+; CHECK-CANO-NEXT:     5f5:	ret                                    funcA:2
+; CHECK: <funcLeaf>:
+; CHECK-NEXT:     600:	mov	eax, edi                           funcLeaf:1
+; CHECK-NEXT:     602:	mov	edx, dword ptr [rip + 2099736]     funcLeaf:2
+; CHECK-NEXT:     608:	mov	ecx, edx                           fib:2 @ funcLeaf:2
+; CHECK-NEXT:     60a:	add	ecx, 3                             fib:2 @ funcLeaf:2
+; CHECK-NEXT:     60d:	cmp	edx, 3                             fib:2 @ funcLeaf:2
+; CHECK-NEXT:     610:	cmovl	ecx, edx                         fib:2 @ funcLeaf:2
+; CHECK-NEXT:     613:	sub	eax, ecx                           funcLeaf:2
+; CHECK-NEXT:     615:	ret                                    funcLeaf:3
+; CHECK: <fib>:
+; CHECK-NEXT:     620:	mov	eax, edi                           fib:2
+; CHECK-NEXT:     622:	add	eax, 3                             fib:2
+; CHECK-NEXT:     625:	cmp	edi, 3                             fib:2
+; CHECK-NEXT:     628:	cmovl	eax, edi                         fib:2
+; CHECK-NEXT:     62b:	ret                                    fib:8
+
+; symbolize.perfbin is from the following compile commands:
+; clang %S/Inputs/symbolize.ll -shared -fPIC -o %S/Inputs/symbolize.perfbin
\ No newline at end of file

diff  --git a/llvm/tools/llvm-profgen/PerfReader.cpp b/llvm/tools/llvm-profgen/PerfReader.cpp
index a9805cfa3550..e1f60adbb8e6 100644
--- a/llvm/tools/llvm-profgen/PerfReader.cpp
+++ b/llvm/tools/llvm-profgen/PerfReader.cpp
@@ -311,18 +311,46 @@ void PerfReader::updateBinaryAddress(const MMapEvent &Event) {
   auto I = BinaryTable.find(BinaryName);
   // Drop the event which doesn't belong to user-provided binaries
   // or if its image is loaded at the same address
-  if (I == BinaryTable.end() || Event.BaseAddress == I->second.getBaseAddress())
+  if (I == BinaryTable.end() || Event.Address == I->second.getBaseAddress())
     return;
 
   ProfiledBinary &Binary = I->second;
 
-  // A binary image could be uploaded and then reloaded at 
diff erent
-  // place, so update the address map here
-  AddrToBinaryMap.erase(Binary.getBaseAddress());
-  AddrToBinaryMap[Event.BaseAddress] = &Binary;
-
-  // Update binary load address.
-  Binary.setBaseAddress(Event.BaseAddress);
+  if (Event.Offset == Binary.getTextSegmentOffset()) {
+    // A binary image could be unloaded and then reloaded at 
diff erent
+    // place, so update the address map here.
+    // Only update for the first executable segment and assume all other
+    // segments are loaded at consecutive memory addresses, which is the case on
+    // X64.
+    AddrToBinaryMap.erase(Binary.getBaseAddress());
+    AddrToBinaryMap[Event.Address] = &Binary;
+
+    // Update binary load address.
+    Binary.setBaseAddress(Event.Address);
+  } else {
+    // Verify segments are loaded consecutively.
+    const auto &Offsets = Binary.getTextSegmentOffsets();
+    auto It = std::lower_bound(Offsets.begin(), Offsets.end(), Event.Offset);
+    if (It != Offsets.end() && *It == Event.Offset) {
+      // The event is for loading a separate executable segment.
+      auto I = std::distance(Offsets.begin(), It);
+      const auto &PreferredAddrs = Binary.getPreferredTextSegmentAddresses();
+      if (PreferredAddrs[I] - Binary.getPreferredBaseAddress() !=
+          Event.Address - Binary.getBaseAddress())
+        exitWithError("Executable segments not loaded consecutively");
+    } else {
+      if (It == Offsets.begin())
+        exitWithError("File offset not found");
+      else {
+        // Find the segment the event falls in. A large segment could be loaded
+        // via multiple mmap calls with consecutive memory addresses.
+        --It;
+        assert(*It < Event.Offset);
+        if (Event.Offset - *It != Event.Address - Binary.getBaseAddress())
+          exitWithError("Segment not loaded by consecutive mmaps");
+      }
+    }
+  }
 }
 
 ProfiledBinary *PerfReader::getBinary(uint64_t Address) {
@@ -637,14 +665,14 @@ void PerfReader::parseMMap2Event(TraceStream &TraceIt) {
   }
   MMapEvent Event;
   Fields[PID].getAsInteger(10, Event.PID);
-  Fields[BASE_ADDRESS].getAsInteger(0, Event.BaseAddress);
+  Fields[BASE_ADDRESS].getAsInteger(0, Event.Address);
   Fields[MMAPPED_SIZE].getAsInteger(0, Event.Size);
   Fields[PAGE_OFFSET].getAsInteger(0, Event.Offset);
   Event.BinaryPath = Fields[BINARY_PATH];
   updateBinaryAddress(Event);
   if (ShowMmapEvents) {
     outs() << "Mmap: Binary " << Event.BinaryPath << " loaded at "
-           << format("0x%" PRIx64 ":", Event.BaseAddress) << " \n";
+           << format("0x%" PRIx64 ":", Event.Address) << " \n";
   }
   TraceIt.advance();
 }

diff  --git a/llvm/tools/llvm-profgen/PerfReader.h b/llvm/tools/llvm-profgen/PerfReader.h
index 27b307d809b8..05bf2d698c52 100644
--- a/llvm/tools/llvm-profgen/PerfReader.h
+++ b/llvm/tools/llvm-profgen/PerfReader.h
@@ -595,7 +595,7 @@ class PerfReader {
   // The parsed MMap event
   struct MMapEvent {
     uint64_t PID = 0;
-    uint64_t BaseAddress = 0;
+    uint64_t Address = 0;
     uint64_t Size = 0;
     uint64_t Offset = 0;
     StringRef BinaryPath;

diff  --git a/llvm/tools/llvm-profgen/ProfiledBinary.cpp b/llvm/tools/llvm-profgen/ProfiledBinary.cpp
index afca9eab1da0..3f0ee4a13840 100644
--- a/llvm/tools/llvm-profgen/ProfiledBinary.cpp
+++ b/llvm/tools/llvm-profgen/ProfiledBinary.cpp
@@ -52,38 +52,6 @@ static const Target *getTarget(const ObjectFile *Obj) {
   return TheTarget;
 }
 
-template <class ELFT>
-static uint64_t getELFImageLMAForSec(const ELFFile<ELFT> &Obj,
-                                     const object::ELFSectionRef &Sec,
-                                     StringRef FileName) {
-  // Search for a PT_LOAD segment containing the requested section. Return this
-  // segment's p_addr as the image load address for the section.
-  const auto &PhdrRange = unwrapOrError(Obj.program_headers(), FileName);
-  for (const typename ELFT::Phdr &Phdr : PhdrRange)
-    if ((Phdr.p_type == ELF::PT_LOAD) && (Phdr.p_vaddr <= Sec.getAddress()) &&
-        (Phdr.p_vaddr + Phdr.p_memsz > Sec.getAddress()))
-      // Segments will always be loaded at a page boundary.
-      return Phdr.p_paddr & ~(Phdr.p_align - 1U);
-  return 0;
-}
-
-// Get the image load address for a specific section. Note that an image is
-// loaded by segments (a group of sections) and segments may not be consecutive
-// in memory.
-static uint64_t getELFImageLMAForSec(const object::ELFSectionRef &Sec) {
-  if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Sec.getObject()))
-    return getELFImageLMAForSec(ELFObj->getELFFile(), Sec,
-                                ELFObj->getFileName());
-  else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Sec.getObject()))
-    return getELFImageLMAForSec(ELFObj->getELFFile(), Sec,
-                                ELFObj->getFileName());
-  else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Sec.getObject()))
-    return getELFImageLMAForSec(ELFObj->getELFFile(), Sec,
-                                ELFObj->getFileName());
-  const auto *ELFObj = cast<ELF64BEObjectFile>(Sec.getObject());
-  return getELFImageLMAForSec(ELFObj->getELFFile(), Sec, ELFObj->getFileName());
-}
-
 void ProfiledBinary::load() {
   // Attempt to open the binary.
   OwningBinary<Binary> OBinary = unwrapOrError(createBinary(Path), Path);
@@ -99,8 +67,8 @@ void ProfiledBinary::load() {
     exitWithError("unsupported target", TheTriple.getTriple());
   LLVM_DEBUG(dbgs() << "Loading " << Path << "\n");
 
-  // Find the preferred base address for text sections.
-  setPreferredBaseAddress(Obj);
+  // Find the preferred load address for text sections.
+  setPreferredTextSegmentAddresses(Obj);
 
   // Decode pseudo probe related section
   decodePseudoProbe(Obj);
@@ -172,16 +140,32 @@ ProfiledBinary::getExpandedContextStr(const SmallVectorImpl<uint64_t> &Stack,
   return OContextStr.str();
 }
 
-void ProfiledBinary::setPreferredBaseAddress(const ELFObjectFileBase *Obj) {
-  for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end();
-       SI != SE; ++SI) {
-    const SectionRef &Section = *SI;
-    if (Section.isText()) {
-      PreferredBaseAddress = getELFImageLMAForSec(Section);
-      return;
-    }
+template <class ELFT>
+void ProfiledBinary::setPreferredTextSegmentAddresses(const ELFFile<ELFT> &Obj, StringRef FileName) {
+  const auto &PhdrRange = unwrapOrError(Obj.program_headers(), FileName);
+  for (const typename ELFT::Phdr &Phdr : PhdrRange) {
+    if ((Phdr.p_type == ELF::PT_LOAD) && (Phdr.p_flags & ELF::PF_X)) {
+        // Segments will always be loaded at a page boundary.
+        PreferredTextSegmentAddresses.push_back(Phdr.p_vaddr & ~(Phdr.p_align - 1U));
+        TextSegmentOffsets.push_back(Phdr.p_offset & ~(Phdr.p_align - 1U));
+      }
   }
-  exitWithError("no text section found", Obj->getFileName());
+
+  if (PreferredTextSegmentAddresses.empty())
+    exitWithError("no executable segment found", FileName);
+}
+
+void ProfiledBinary::setPreferredTextSegmentAddresses(const ELFObjectFileBase *Obj) {
+  if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj))
+    setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName());
+  else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj))
+    setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName());
+  else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj))
+    setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName());
+  else if (const auto *ELFObj = cast<ELF64BEObjectFile>(Obj))
+    setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName());
+  else
+    llvm_unreachable("invalid ELF object format");
 }
 
 void ProfiledBinary::decodePseudoProbe(const ELFObjectFileBase *Obj) {
@@ -212,11 +196,11 @@ bool ProfiledBinary::dissassembleSymbol(std::size_t SI, ArrayRef<uint8_t> Bytes,
                                         SectionSymbolsTy &Symbols,
                                         const SectionRef &Section) {
   std::size_t SE = Symbols.size();
-  uint64_t SectionOffset = Section.getAddress() - PreferredBaseAddress;
+  uint64_t SectionOffset = Section.getAddress() - getPreferredBaseAddress();
   uint64_t SectSize = Section.getSize();
-  uint64_t StartOffset = Symbols[SI].Addr - PreferredBaseAddress;
+  uint64_t StartOffset = Symbols[SI].Addr - getPreferredBaseAddress();
   uint64_t EndOffset = (SI + 1 < SE)
-                           ? Symbols[SI + 1].Addr - PreferredBaseAddress
+                           ? Symbols[SI + 1].Addr - getPreferredBaseAddress()
                            : SectionOffset + SectSize;
   if (StartOffset >= EndOffset)
     return true;
@@ -244,16 +228,16 @@ bool ProfiledBinary::dissassembleSymbol(std::size_t SI, ArrayRef<uint8_t> Bytes,
     // Disassemble an instruction.
     bool Disassembled =
         DisAsm->getInstruction(Inst, Size, Bytes.slice(Offset - SectionOffset),
-                               Offset + PreferredBaseAddress, nulls());
+                               Offset + getPreferredBaseAddress(), nulls());
     if (Size == 0)
       Size = 1;
 
     if (ShowDisassemblyOnly) {
       if (ShowPseudoProbe) {
         ProbeDecoder.printProbeForAddress(outs(),
-                                          Offset + PreferredBaseAddress);
+                                          Offset + getPreferredBaseAddress());
       }
-      outs() << format("%8" PRIx64 ":", Offset);
+      outs() << format("%8" PRIx64 ":", Offset + getPreferredBaseAddress());
       size_t Start = outs().tell();
       if (Disassembled)
         IPrinter->printInst(&Inst, Offset + Size, "", *STI.get(), outs());
@@ -378,7 +362,7 @@ void ProfiledBinary::disassemble(const ELFObjectFileBase *Obj) {
     if (!Section.isText())
       continue;
 
-    uint64_t ImageLoadAddr = PreferredBaseAddress;
+    uint64_t ImageLoadAddr = getPreferredBaseAddress();
     uint64_t SectionOffset = Section.getAddress() - ImageLoadAddr;
     uint64_t SectSize = Section.getSize();
     if (!SectSize)
@@ -390,8 +374,9 @@ void ProfiledBinary::disassemble(const ELFObjectFileBase *Obj) {
     if (ShowDisassemblyOnly) {
       StringRef SectionName = unwrapOrError(Section.getName(), FileName);
       outs() << "\nDisassembly of section " << SectionName;
-      outs() << " [" << format("0x%" PRIx64, SectionOffset) << ", "
-             << format("0x%" PRIx64, SectionOffset + SectSize) << "]:\n\n";
+      outs() << " [" << format("0x%" PRIx64, Section.getAddress()) << ", "
+             << format("0x%" PRIx64, Section.getAddress() + SectSize)
+             << "]:\n\n";
     }
 
     // Get the section data.
@@ -424,7 +409,7 @@ FrameLocationStack ProfiledBinary::symbolize(const InstructionPointer &IP,
                                              bool UseCanonicalFnName) {
   assert(this == IP.Binary &&
          "Binary should only symbolize its own instruction");
-  auto Addr = object::SectionedAddress{IP.Offset + PreferredBaseAddress,
+  auto Addr = object::SectionedAddress{IP.Offset + getPreferredBaseAddress(),
                                        object::SectionedAddress::UndefSection};
   DIInliningInfo InlineStack =
       unwrapOrError(Symbolizer->symbolizeInlinedCode(Path, Addr), getName());

diff  --git a/llvm/tools/llvm-profgen/ProfiledBinary.h b/llvm/tools/llvm-profgen/ProfiledBinary.h
index b56574e0bf6f..8b456d4f669c 100644
--- a/llvm/tools/llvm-profgen/ProfiledBinary.h
+++ b/llvm/tools/llvm-profgen/ProfiledBinary.h
@@ -99,10 +99,13 @@ class ProfiledBinary {
   std::string Path;
   // The target triple.
   Triple TheTriple;
-  // The runtime base address that the executable sections are loaded at.
-  mutable uint64_t BaseAddress = 0;
-  // The preferred base address that the executable sections are loaded at.
-  uint64_t PreferredBaseAddress = 0;
+  // The runtime base address that the first executable segment is loaded at.
+  uint64_t BaseAddress;
+  // The preferred load address of each executable segment.
+  std::vector<uint64_t> PreferredTextSegmentAddresses;
+  // The file offset of each executable segment.
+  std::vector<uint64_t> TextSegmentOffsets;
+
   // Mutiple MC component info
   std::unique_ptr<const MCRegisterInfo> MRI;
   std::unique_ptr<const MCAsmInfo> AsmInfo;
@@ -136,7 +139,10 @@ class ProfiledBinary {
 
   bool UsePseudoProbes = false;
 
-  void setPreferredBaseAddress(const ELFObjectFileBase *O);
+  void setPreferredTextSegmentAddresses(const ELFObjectFileBase *O);
+
+  template <class ELFT>
+  void setPreferredTextSegmentAddresses(const ELFFile<ELFT> &Obj, StringRef FileName);
 
   void decodePseudoProbe(const ELFObjectFileBase *Obj);
 
@@ -174,8 +180,8 @@ class ProfiledBinary {
     setupSymbolizer();
     load();
   }
-  uint64_t virtualAddrToOffset(uint64_t VitualAddress) const {
-    return VitualAddress - BaseAddress;
+  uint64_t virtualAddrToOffset(uint64_t VirtualAddress) const {
+    return VirtualAddress - BaseAddress;
   }
   uint64_t offsetToVirtualAddr(uint64_t Offset) const {
     return Offset + BaseAddress;
@@ -184,7 +190,17 @@ class ProfiledBinary {
   StringRef getName() const { return llvm::sys::path::filename(Path); }
   uint64_t getBaseAddress() const { return BaseAddress; }
   void setBaseAddress(uint64_t Address) { BaseAddress = Address; }
-  uint64_t getPreferredBaseAddress() const { return PreferredBaseAddress; }
+  
+  // Return the preferred load address for the first executable segment.
+  uint64_t getPreferredBaseAddress() const { return PreferredTextSegmentAddresses[0]; }
+  // Return the file offset for the first executable segment.
+  uint64_t getTextSegmentOffset() const { return TextSegmentOffsets[0]; }
+  const std::vector<uint64_t> &getPreferredTextSegmentAddresses() const {
+    return PreferredTextSegmentAddresses;
+  }
+  const std::vector<uint64_t> &getTextSegmentOffsets() const {
+    return TextSegmentOffsets;
+  }
 
   bool addressIsCode(uint64_t Address) const {
     uint64_t Offset = virtualAddrToOffset(Address);


        


More information about the llvm-commits mailing list