diff mbox series

[RFC,v3,11/12] powerpc: Remove unreachable() from WARN_ON()

Message ID 20220624183238.388144-12-sv@linux.ibm.com (mailing list archive)
State Handled Elsewhere
Headers show
Series objtool: Enable and implement --mcount option on powerpc | expand

Commit Message

Sathvika Vasireddy June 24, 2022, 6:32 p.m. UTC
objtool is throwing *unannotated intra-function call*
warnings with a few instructions that are marked
unreachable. Remove unreachable() from WARN_ON()
to fix these warnings, as the codegen remains same
with and without unreachable() in WARN_ON().

Signed-off-by: Sathvika Vasireddy <sv@linux.ibm.com>
---
 arch/powerpc/include/asm/bug.h | 1 -
 1 file changed, 1 deletion(-)

Comments

Christophe Leroy June 25, 2022, 6:46 a.m. UTC | #1
Le 24/06/2022 à 20:32, Sathvika Vasireddy a écrit :
> objtool is throwing *unannotated intra-function call*
> warnings with a few instructions that are marked
> unreachable. Remove unreachable() from WARN_ON()
> to fix these warnings, as the codegen remains same
> with and without unreachable() in WARN_ON().

Did you try the two exemples described in commit 1e688dd2a3d6 
("powerpc/bug: Provide better flexibility to WARN_ON/__WARN_FLAGS() with 
asm goto") ?

Without your patch:

00000640 <test>:
  640:	81 23 00 84 	lwz     r9,132(r3)
  644:	71 29 40 00 	andi.   r9,r9,16384
  648:	40 82 00 0c 	bne     654 <test+0x14>
  64c:	80 63 00 0c 	lwz     r3,12(r3)
  650:	4e 80 00 20 	blr
  654:	0f e0 00 00 	twui    r0,0

00000658 <test9w>:
  658:	2c 04 00 00 	cmpwi   r4,0
  65c:	41 82 00 0c 	beq     668 <test9w+0x10>
  660:	7c 63 23 96 	divwu   r3,r3,r4
  664:	4e 80 00 20 	blr
  668:	0f e0 00 00 	twui    r0,0
  66c:	38 60 00 00 	li      r3,0
  670:	4e 80 00 20 	blr


With your patch:

00000640 <test>:
  640:	81 23 00 84 	lwz     r9,132(r3)
  644:	71 29 40 00 	andi.   r9,r9,16384
  648:	40 82 00 0c 	bne     654 <test+0x14>
  64c:	80 63 00 0c 	lwz     r3,12(r3)
  650:	4e 80 00 20 	blr
  654:	0f e0 00 00 	twui    r0,0
  658:	4b ff ff f4 	b       64c <test+0xc>		<==

0000065c <test9w>:
  65c:	2c 04 00 00 	cmpwi   r4,0
  660:	41 82 00 0c 	beq     66c <test9w+0x10>
  664:	7c 63 23 96 	divwu   r3,r3,r4
  668:	4e 80 00 20 	blr
  66c:	0f e0 00 00 	twui    r0,0
  670:	38 60 00 00 	li      r3,0			<==
  674:	4e 80 00 20 	blr				<==
  678:	38 60 00 00 	li      r3,0
  67c:	4e 80 00 20 	blr


Christophe

> 
> Signed-off-by: Sathvika Vasireddy <sv@linux.ibm.com>
> ---
>   arch/powerpc/include/asm/bug.h | 1 -
>   1 file changed, 1 deletion(-)
> 
> diff --git a/arch/powerpc/include/asm/bug.h b/arch/powerpc/include/asm/bug.h
> index ecbae1832de3..df6c11e008b9 100644
> --- a/arch/powerpc/include/asm/bug.h
> +++ b/arch/powerpc/include/asm/bug.h
> @@ -97,7 +97,6 @@
>   	__label__ __label_warn_on;				\
>   								\
>   	WARN_ENTRY("twi 31, 0, 0", BUGFLAG_WARNING | (flags), __label_warn_on); \
> -	unreachable();						\
>   								\
>   __label_warn_on:						\
>   	break;							\
Sathvika Vasireddy June 27, 2022, 3:21 p.m. UTC | #2
On 25/06/22 12:16, Christophe Leroy wrote:
>
> Le 24/06/2022 à 20:32, Sathvika Vasireddy a écrit :
>> objtool is throwing *unannotated intra-function call*
>> warnings with a few instructions that are marked
>> unreachable. Remove unreachable() from WARN_ON()
>> to fix these warnings, as the codegen remains same
>> with and without unreachable() in WARN_ON().
> Did you try the two exemples described in commit 1e688dd2a3d6
> ("powerpc/bug: Provide better flexibility to WARN_ON/__WARN_FLAGS() with
> asm goto") ?
>
> Without your patch:
>
> 00000640 <test>:
>    640:	81 23 00 84 	lwz     r9,132(r3)
>    644:	71 29 40 00 	andi.   r9,r9,16384
>    648:	40 82 00 0c 	bne     654 <test+0x14>
>    64c:	80 63 00 0c 	lwz     r3,12(r3)
>    650:	4e 80 00 20 	blr
>    654:	0f e0 00 00 	twui    r0,0
>
> 00000658 <test9w>:
>    658:	2c 04 00 00 	cmpwi   r4,0
>    65c:	41 82 00 0c 	beq     668 <test9w+0x10>
>    660:	7c 63 23 96 	divwu   r3,r3,r4
>    664:	4e 80 00 20 	blr
>    668:	0f e0 00 00 	twui    r0,0
>    66c:	38 60 00 00 	li      r3,0
>    670:	4e 80 00 20 	blr
>
>
> With your patch:
>
> 00000640 <test>:
>    640:	81 23 00 84 	lwz     r9,132(r3)
>    644:	71 29 40 00 	andi.   r9,r9,16384
>    648:	40 82 00 0c 	bne     654 <test+0x14>
>    64c:	80 63 00 0c 	lwz     r3,12(r3)
>    650:	4e 80 00 20 	blr
>    654:	0f e0 00 00 	twui    r0,0
>    658:	4b ff ff f4 	b       64c <test+0xc>		<==
>
> 0000065c <test9w>:
>    65c:	2c 04 00 00 	cmpwi   r4,0
>    660:	41 82 00 0c 	beq     66c <test9w+0x10>
>    664:	7c 63 23 96 	divwu   r3,r3,r4
>    668:	4e 80 00 20 	blr
>    66c:	0f e0 00 00 	twui    r0,0
>    670:	38 60 00 00 	li      r3,0			<==
>    674:	4e 80 00 20 	blr				<==
>    678:	38 60 00 00 	li      r3,0
>    67c:	4e 80 00 20 	blr
>
The builtin variant of unreachable (__builtin_unreachable()) works,
and the codegen remains the same.

How about using that instead of unreachable() ?


- Sathvika
Sathvika Vasireddy June 27, 2022, 3:35 p.m. UTC | #3
On 25/06/22 12:16, Christophe Leroy wrote:
>
> Le 24/06/2022 à 20:32, Sathvika Vasireddy a écrit :
>> objtool is throwing *unannotated intra-function call*
>> warnings with a few instructions that are marked
>> unreachable. Remove unreachable() from WARN_ON()
>> to fix these warnings, as the codegen remains same
>> with and without unreachable() in WARN_ON().
> Did you try the two exemples described in commit 1e688dd2a3d6
> ("powerpc/bug: Provide better flexibility to WARN_ON/__WARN_FLAGS() with
> asm goto") ?
>
> Without your patch:
>
> 00000640 <test>:
>    640:	81 23 00 84 	lwz     r9,132(r3)
>    644:	71 29 40 00 	andi.   r9,r9,16384
>    648:	40 82 00 0c 	bne     654 <test+0x14>
>    64c:	80 63 00 0c 	lwz     r3,12(r3)
>    650:	4e 80 00 20 	blr
>    654:	0f e0 00 00 	twui    r0,0
>
> 00000658 <test9w>:
>    658:	2c 04 00 00 	cmpwi   r4,0
>    65c:	41 82 00 0c 	beq     668 <test9w+0x10>
>    660:	7c 63 23 96 	divwu   r3,r3,r4
>    664:	4e 80 00 20 	blr
>    668:	0f e0 00 00 	twui    r0,0
>    66c:	38 60 00 00 	li      r3,0
>    670:	4e 80 00 20 	blr
>
>
> With your patch:
>
> 00000640 <test>:
>    640:	81 23 00 84 	lwz     r9,132(r3)
>    644:	71 29 40 00 	andi.   r9,r9,16384
>    648:	40 82 00 0c 	bne     654 <test+0x14>
>    64c:	80 63 00 0c 	lwz     r3,12(r3)
>    650:	4e 80 00 20 	blr
>    654:	0f e0 00 00 	twui    r0,0
>    658:	4b ff ff f4 	b       64c <test+0xc>		<==
>
> 0000065c <test9w>:
>    65c:	2c 04 00 00 	cmpwi   r4,0
>    660:	41 82 00 0c 	beq     66c <test9w+0x10>
>    664:	7c 63 23 96 	divwu   r3,r3,r4
>    668:	4e 80 00 20 	blr
>    66c:	0f e0 00 00 	twui    r0,0
>    670:	38 60 00 00 	li      r3,0			<==
>    674:	4e 80 00 20 	blr				<==
>    678:	38 60 00 00 	li      r3,0
>    67c:	4e 80 00 20 	blr
>
The builtin variant of unreachable (__builtin_unreachable()) works.

How about using that instead of unreachable() ?


- Sathvika
Christophe Leroy June 27, 2022, 3:46 p.m. UTC | #4
Le 27/06/2022 à 17:35, Sathvika Vasireddy a écrit :
> 
> On 25/06/22 12:16, Christophe Leroy wrote:
>>
>> Le 24/06/2022 à 20:32, Sathvika Vasireddy a écrit :
>>> objtool is throwing *unannotated intra-function call*
>>> warnings with a few instructions that are marked
>>> unreachable. Remove unreachable() from WARN_ON()
>>> to fix these warnings, as the codegen remains same
>>> with and without unreachable() in WARN_ON().
>> Did you try the two exemples described in commit 1e688dd2a3d6
>> ("powerpc/bug: Provide better flexibility to WARN_ON/__WARN_FLAGS() with
>> asm goto") ?
>>
>> Without your patch:
>>
>> 00000640 <test>:
>>    640:    81 23 00 84     lwz     r9,132(r3)
>>    644:    71 29 40 00     andi.   r9,r9,16384
>>    648:    40 82 00 0c     bne     654 <test+0x14>
>>    64c:    80 63 00 0c     lwz     r3,12(r3)
>>    650:    4e 80 00 20     blr
>>    654:    0f e0 00 00     twui    r0,0
>>
>> 00000658 <test9w>:
>>    658:    2c 04 00 00     cmpwi   r4,0
>>    65c:    41 82 00 0c     beq     668 <test9w+0x10>
>>    660:    7c 63 23 96     divwu   r3,r3,r4
>>    664:    4e 80 00 20     blr
>>    668:    0f e0 00 00     twui    r0,0
>>    66c:    38 60 00 00     li      r3,0
>>    670:    4e 80 00 20     blr
>>
>>
>> With your patch:
>>
>> 00000640 <test>:
>>    640:    81 23 00 84     lwz     r9,132(r3)
>>    644:    71 29 40 00     andi.   r9,r9,16384
>>    648:    40 82 00 0c     bne     654 <test+0x14>
>>    64c:    80 63 00 0c     lwz     r3,12(r3)
>>    650:    4e 80 00 20     blr
>>    654:    0f e0 00 00     twui    r0,0
>>    658:    4b ff ff f4     b       64c <test+0xc>        <==
>>
>> 0000065c <test9w>:
>>    65c:    2c 04 00 00     cmpwi   r4,0
>>    660:    41 82 00 0c     beq     66c <test9w+0x10>
>>    664:    7c 63 23 96     divwu   r3,r3,r4
>>    668:    4e 80 00 20     blr
>>    66c:    0f e0 00 00     twui    r0,0
>>    670:    38 60 00 00     li      r3,0            <==
>>    674:    4e 80 00 20     blr                <==
>>    678:    38 60 00 00     li      r3,0
>>    67c:    4e 80 00 20     blr
>>
> The builtin variant of unreachable (__builtin_unreachable()) works.
> 
> How about using that instead of unreachable() ?
> 

That seems odd.

Look at linux/compiler.h

It seems like unreachable() exists to help objtool.

Christophe
Christophe Leroy June 29, 2022, 6:30 p.m. UTC | #5
Hi Sathvika,

Adding ARM people as they seem to face the same kind of problem (see 
https://patchwork.kernel.org/project/linux-kbuild/patch/20220623014917.199563-33-chenzhongjin@huawei.com/)

Le 27/06/2022 à 17:35, Sathvika Vasireddy a écrit :
> 
> On 25/06/22 12:16, Christophe Leroy wrote:
>>
>> Le 24/06/2022 à 20:32, Sathvika Vasireddy a écrit :
>>> objtool is throwing *unannotated intra-function call*
>>> warnings with a few instructions that are marked
>>> unreachable. Remove unreachable() from WARN_ON()
>>> to fix these warnings, as the codegen remains same
>>> with and without unreachable() in WARN_ON().
>> Did you try the two exemples described in commit 1e688dd2a3d6
>> ("powerpc/bug: Provide better flexibility to WARN_ON/__WARN_FLAGS() with
>> asm goto") ?
>>
>> Without your patch:
>>
>> 00000640 <test>:
>>    640:    81 23 00 84     lwz     r9,132(r3)
>>    644:    71 29 40 00     andi.   r9,r9,16384
>>    648:    40 82 00 0c     bne     654 <test+0x14>
>>    64c:    80 63 00 0c     lwz     r3,12(r3)
>>    650:    4e 80 00 20     blr
>>    654:    0f e0 00 00     twui    r0,0
>>
>> 00000658 <test9w>:
>>    658:    2c 04 00 00     cmpwi   r4,0
>>    65c:    41 82 00 0c     beq     668 <test9w+0x10>
>>    660:    7c 63 23 96     divwu   r3,r3,r4
>>    664:    4e 80 00 20     blr
>>    668:    0f e0 00 00     twui    r0,0
>>    66c:    38 60 00 00     li      r3,0
>>    670:    4e 80 00 20     blr
>>
>>
>> With your patch:
>>
>> 00000640 <test>:
>>    640:    81 23 00 84     lwz     r9,132(r3)
>>    644:    71 29 40 00     andi.   r9,r9,16384
>>    648:    40 82 00 0c     bne     654 <test+0x14>
>>    64c:    80 63 00 0c     lwz     r3,12(r3)
>>    650:    4e 80 00 20     blr
>>    654:    0f e0 00 00     twui    r0,0
>>    658:    4b ff ff f4     b       64c <test+0xc>        <==
>>
>> 0000065c <test9w>:
>>    65c:    2c 04 00 00     cmpwi   r4,0
>>    660:    41 82 00 0c     beq     66c <test9w+0x10>
>>    664:    7c 63 23 96     divwu   r3,r3,r4
>>    668:    4e 80 00 20     blr
>>    66c:    0f e0 00 00     twui    r0,0
>>    670:    38 60 00 00     li      r3,0            <==
>>    674:    4e 80 00 20     blr                <==
>>    678:    38 60 00 00     li      r3,0
>>    67c:    4e 80 00 20     blr
>>
> The builtin variant of unreachable (__builtin_unreachable()) works.
> 
> How about using that instead of unreachable() ?
> 
> 

In fact the problem comes from the macro annotate_unreachable() which is 
called by unreachable() before calling __build_unreachable().

Seems like this macro adds (after the unconditional trap twui) a call to 
an empty function whose address is listed in section .discard.unreachable

     1c78:       00 00 e0 0f     twui    r0,0
     1c7c:       55 e7 ff 4b     bl      3d0 
<qdisc_root_sleeping_lock.part.0>


RELOCATION RECORDS FOR [.discard.unreachable]:
OFFSET           TYPE              VALUE
0000000000000000 R_PPC64_REL32     .text+0x00000000000003d0

The problem is that that function has size 0:

00000000000003d0 l     F .text	0000000000000000 
qdisc_root_sleeping_lock.part.0


And objtool is not prepared for a function with size 0.


The following changes to objtool seem to fix the problem, most warning 
are gone with that change.

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 63218f5799c2..37c0a268b7ea 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -77,6 +77,8 @@ static int symbol_by_offset(const void *key, const 
struct rb_node *node)

  	if (*o < s->offset)
  		return -1;
+	if (*o == s->offset && !s->len)
+		return 0;
  	if (*o >= s->offset + s->len)
  		return 1;

@@ -400,7 +402,7 @@ static void elf_add_symbol(struct elf *elf, struct 
symbol *sym)
  	 * Don't store empty STT_NOTYPE symbols in the rbtree.  They
  	 * can exist within a function, confusing the sorting.
  	 */
-	if (!sym->len)
+	if (sym->type == STT_NOTYPE && !sym->len)
  		rb_erase(&sym->node, &sym->sec->symbol_tree);
  }

---

I also had objtool running for ever on 
arch/powerpc/sysdev/xics/icp-hv.o, which I fixed with the below hack:

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 51b6dcec8d6a..ef2303ad6381 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -529,7 +529,7 @@ static struct instruction *find_last_insn(struct 
objtool_file *file,
  	unsigned int offset;
  	unsigned int end = (sec->sh.sh_size > 10) ? sec->sh.sh_size - 10 : 0;

-	for (offset = sec->sh.sh_size - 1; offset >= end && !insn; offset--)
+	for (offset = sec->sh.sh_size - 1; offset && offset >= end && !insn; 
offset--)
  		insn = find_insn(file, sec, offset);

  	return insn;
---

Now I only have the following two warnings:

arch/powerpc/sysdev/xics/icp-hv.o: warning: objtool: can't find 
unreachable insn at .text.unlikely+0x0
drivers/crypto/vmx/aesp8-ppc.o: warning: objtool: 
aes_p8_set_encrypt_key+0x44: unannotated intra-function call

The first one is linked to the infinite loop I hacked. So I now have to 
understand what the problem really is.

The second one is an assembly file aesp8-ppc.S which lacks the changes 
you did in other assembly files in patch 12.

Christophe
Naveen N. Rao June 30, 2022, 8:05 a.m. UTC | #6
Christophe Leroy wrote:
> Hi Sathvika,
> 
> Adding ARM people as they seem to face the same kind of problem (see 
> https://patchwork.kernel.org/project/linux-kbuild/patch/20220623014917.199563-33-chenzhongjin@huawei.com/)
> 
> Le 27/06/2022 à 17:35, Sathvika Vasireddy a écrit :
>> 
>> On 25/06/22 12:16, Christophe Leroy wrote:
>>>
>>> Le 24/06/2022 à 20:32, Sathvika Vasireddy a écrit :
>>>> objtool is throwing *unannotated intra-function call*
>>>> warnings with a few instructions that are marked
>>>> unreachable. Remove unreachable() from WARN_ON()
>>>> to fix these warnings, as the codegen remains same
>>>> with and without unreachable() in WARN_ON().
>>> Did you try the two exemples described in commit 1e688dd2a3d6
>>> ("powerpc/bug: Provide better flexibility to WARN_ON/__WARN_FLAGS() with
>>> asm goto") ?
>>>
>>> Without your patch:
>>>
>>> 00000640 <test>:
>>>    640:    81 23 00 84     lwz     r9,132(r3)
>>>    644:    71 29 40 00     andi.   r9,r9,16384
>>>    648:    40 82 00 0c     bne     654 <test+0x14>
>>>    64c:    80 63 00 0c     lwz     r3,12(r3)
>>>    650:    4e 80 00 20     blr
>>>    654:    0f e0 00 00     twui    r0,0
>>>
>>> 00000658 <test9w>:
>>>    658:    2c 04 00 00     cmpwi   r4,0
>>>    65c:    41 82 00 0c     beq     668 <test9w+0x10>
>>>    660:    7c 63 23 96     divwu   r3,r3,r4
>>>    664:    4e 80 00 20     blr
>>>    668:    0f e0 00 00     twui    r0,0
>>>    66c:    38 60 00 00     li      r3,0
>>>    670:    4e 80 00 20     blr
>>>
>>>
>>> With your patch:
>>>
>>> 00000640 <test>:
>>>    640:    81 23 00 84     lwz     r9,132(r3)
>>>    644:    71 29 40 00     andi.   r9,r9,16384
>>>    648:    40 82 00 0c     bne     654 <test+0x14>
>>>    64c:    80 63 00 0c     lwz     r3,12(r3)
>>>    650:    4e 80 00 20     blr
>>>    654:    0f e0 00 00     twui    r0,0
>>>    658:    4b ff ff f4     b       64c <test+0xc>        <==
>>>
>>> 0000065c <test9w>:
>>>    65c:    2c 04 00 00     cmpwi   r4,0
>>>    660:    41 82 00 0c     beq     66c <test9w+0x10>
>>>    664:    7c 63 23 96     divwu   r3,r3,r4
>>>    668:    4e 80 00 20     blr
>>>    66c:    0f e0 00 00     twui    r0,0
>>>    670:    38 60 00 00     li      r3,0            <==
>>>    674:    4e 80 00 20     blr                <==
>>>    678:    38 60 00 00     li      r3,0
>>>    67c:    4e 80 00 20     blr
>>>
>> The builtin variant of unreachable (__builtin_unreachable()) works.
>> 
>> How about using that instead of unreachable() ?
>> 
>> 
> 
> In fact the problem comes from the macro annotate_unreachable() which is 
> called by unreachable() before calling __build_unreachable().
> 
> Seems like this macro adds (after the unconditional trap twui) a call to 
> an empty function whose address is listed in section .discard.unreachable
> 
>      1c78:       00 00 e0 0f     twui    r0,0
>      1c7c:       55 e7 ff 4b     bl      3d0 
> <qdisc_root_sleeping_lock.part.0>
> 
> 
> RELOCATION RECORDS FOR [.discard.unreachable]:
> OFFSET           TYPE              VALUE
> 0000000000000000 R_PPC64_REL32     .text+0x00000000000003d0
> 
> The problem is that that function has size 0:
> 
> 00000000000003d0 l     F .text	0000000000000000 
> qdisc_root_sleeping_lock.part.0
> 
> 
> And objtool is not prepared for a function with size 0.

annotate_unreachable() seems to have been introduced in commit 
649ea4d5a624f0 ("objtool: Assume unannotated UD2 instructions are dead 
ends").

Objtool considers 'ud2' instruction to be fatal, so BUG() has 
__builtin_unreachable(), rather than unreachable(). See commit 
bfb1a7c91fb775 ("x86/bug: Merge annotate_reachable() into _BUG_FLAGS() 
asm"). For the same reason, __WARN_FLAGS() is annotated with 
_ASM_REACHABLE so that objtool can differentiate warnings from a BUG().

On powerpc, we use trap variants for both and don't have a special 
instruction for a BUG(). As such, for _WARN_FLAGS(), using 
__builtin_unreachable() suffices to achieve optimal code generation from 
the compiler. Objtool would consider subsequent instructions to be 
reachable. For BUG(), we can continue to use unreachable() so that 
objtool can differentiate these from traps used in warnings.

> 
> The following changes to objtool seem to fix the problem, most warning 
> are gone with that change.
> 
> diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
> index 63218f5799c2..37c0a268b7ea 100644
> --- a/tools/objtool/elf.c
> +++ b/tools/objtool/elf.c
> @@ -77,6 +77,8 @@ static int symbol_by_offset(const void *key, const 
> struct rb_node *node)
> 
>   	if (*o < s->offset)
>   		return -1;
> +	if (*o == s->offset && !s->len)
> +		return 0;
>   	if (*o >= s->offset + s->len)
>   		return 1;
> 
> @@ -400,7 +402,7 @@ static void elf_add_symbol(struct elf *elf, struct 
> symbol *sym)
>   	 * Don't store empty STT_NOTYPE symbols in the rbtree.  They
>   	 * can exist within a function, confusing the sorting.
>   	 */
> -	if (!sym->len)
> +	if (sym->type == STT_NOTYPE && !sym->len)
>   		rb_erase(&sym->node, &sym->sec->symbol_tree);
>   }

Is there a reason to do this, rather than change __WARN_FLAGS() to use 
__builtin_unreachable()? Or, are you seeing an issue with unreachable() 
elsewhere in the kernel?


- Naveen
Christophe Leroy June 30, 2022, 9:58 a.m. UTC | #7
Le 30/06/2022 à 10:05, Naveen N. Rao a écrit :
> Christophe Leroy wrote:
>> Hi Sathvika,
>>
>> Adding ARM people as they seem to face the same kind of problem (see 
>> https://patchwork.kernel.org/project/linux-kbuild/patch/20220623014917.199563-33-chenzhongjin@huawei.com/) 
>>
>>
>> Le 27/06/2022 à 17:35, Sathvika Vasireddy a écrit :
>>>
>>> On 25/06/22 12:16, Christophe Leroy wrote:
>>>>
>>>> Le 24/06/2022 à 20:32, Sathvika Vasireddy a écrit :
>>>>> objtool is throwing *unannotated intra-function call*
>>>>> warnings with a few instructions that are marked
>>>>> unreachable. Remove unreachable() from WARN_ON()
>>>>> to fix these warnings, as the codegen remains same
>>>>> with and without unreachable() in WARN_ON().
>>>> Did you try the two exemples described in commit 1e688dd2a3d6
>>>> ("powerpc/bug: Provide better flexibility to WARN_ON/__WARN_FLAGS() 
>>>> with
>>>> asm goto") ?
>>>>
>>>> Without your patch:
>>>>
>>>> 00000640 <test>:
>>>>    640:    81 23 00 84     lwz     r9,132(r3)
>>>>    644:    71 29 40 00     andi.   r9,r9,16384
>>>>    648:    40 82 00 0c     bne     654 <test+0x14>
>>>>    64c:    80 63 00 0c     lwz     r3,12(r3)
>>>>    650:    4e 80 00 20     blr
>>>>    654:    0f e0 00 00     twui    r0,0
>>>>
>>>> 00000658 <test9w>:
>>>>    658:    2c 04 00 00     cmpwi   r4,0
>>>>    65c:    41 82 00 0c     beq     668 <test9w+0x10>
>>>>    660:    7c 63 23 96     divwu   r3,r3,r4
>>>>    664:    4e 80 00 20     blr
>>>>    668:    0f e0 00 00     twui    r0,0
>>>>    66c:    38 60 00 00     li      r3,0
>>>>    670:    4e 80 00 20     blr
>>>>
>>>>
>>>> With your patch:
>>>>
>>>> 00000640 <test>:
>>>>    640:    81 23 00 84     lwz     r9,132(r3)
>>>>    644:    71 29 40 00     andi.   r9,r9,16384
>>>>    648:    40 82 00 0c     bne     654 <test+0x14>
>>>>    64c:    80 63 00 0c     lwz     r3,12(r3)
>>>>    650:    4e 80 00 20     blr
>>>>    654:    0f e0 00 00     twui    r0,0
>>>>    658:    4b ff ff f4     b       64c <test+0xc>        <==
>>>>
>>>> 0000065c <test9w>:
>>>>    65c:    2c 04 00 00     cmpwi   r4,0
>>>>    660:    41 82 00 0c     beq     66c <test9w+0x10>
>>>>    664:    7c 63 23 96     divwu   r3,r3,r4
>>>>    668:    4e 80 00 20     blr
>>>>    66c:    0f e0 00 00     twui    r0,0
>>>>    670:    38 60 00 00     li      r3,0            <==
>>>>    674:    4e 80 00 20     blr                <==
>>>>    678:    38 60 00 00     li      r3,0
>>>>    67c:    4e 80 00 20     blr
>>>>
>>> The builtin variant of unreachable (__builtin_unreachable()) works.
>>>
>>> How about using that instead of unreachable() ?
>>>
>>>
>>
>> In fact the problem comes from the macro annotate_unreachable() which 
>> is called by unreachable() before calling __build_unreachable().
>>
>> Seems like this macro adds (after the unconditional trap twui) a call 
>> to an empty function whose address is listed in section 
>> .discard.unreachable
>>
>>      1c78:       00 00 e0 0f     twui    r0,0
>>      1c7c:       55 e7 ff 4b     bl      3d0 
>> <qdisc_root_sleeping_lock.part.0>
>>
>>
>> RELOCATION RECORDS FOR [.discard.unreachable]:
>> OFFSET           TYPE              VALUE
>> 0000000000000000 R_PPC64_REL32     .text+0x00000000000003d0
>>
>> The problem is that that function has size 0:
>>
>> 00000000000003d0 l     F .text    0000000000000000 
>> qdisc_root_sleeping_lock.part.0
>>
>>
>> And objtool is not prepared for a function with size 0.
> 
> annotate_unreachable() seems to have been introduced in commit 
> 649ea4d5a624f0 ("objtool: Assume unannotated UD2 instructions are dead 
> ends").
> 
> Objtool considers 'ud2' instruction to be fatal, so BUG() has 
> __builtin_unreachable(), rather than unreachable(). See commit 
> bfb1a7c91fb775 ("x86/bug: Merge annotate_reachable() into _BUG_FLAGS() 
> asm"). For the same reason, __WARN_FLAGS() is annotated with 
> _ASM_REACHABLE so that objtool can differentiate warnings from a BUG().
> 
> On powerpc, we use trap variants for both and don't have a special 
> instruction for a BUG(). As such, for _WARN_FLAGS(), using 
> __builtin_unreachable() suffices to achieve optimal code generation from 
> the compiler. Objtool would consider subsequent instructions to be 
> reachable. For BUG(), we can continue to use unreachable() so that 
> objtool can differentiate these from traps used in warnings.

Not sure I understand what you mean.

__WARN_FLAGS() and BUG() both use 'twui' which is unconditionnal trap, 
as such both are the same.

On the other side, WARN_ON() and BUG_ON() use tlbnei which is a 
conditionnel trap.

> 
>>
>> The following changes to objtool seem to fix the problem, most warning 
>> are gone with that change.
>>
>> diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
>> index 63218f5799c2..37c0a268b7ea 100644
>> --- a/tools/objtool/elf.c
>> +++ b/tools/objtool/elf.c
>> @@ -77,6 +77,8 @@ static int symbol_by_offset(const void *key, const 
>> struct rb_node *node)
>>
>>       if (*o < s->offset)
>>           return -1;
>> +    if (*o == s->offset && !s->len)
>> +        return 0;
>>       if (*o >= s->offset + s->len)
>>           return 1;
>>
>> @@ -400,7 +402,7 @@ static void elf_add_symbol(struct elf *elf, struct 
>> symbol *sym)
>>        * Don't store empty STT_NOTYPE symbols in the rbtree.  They
>>        * can exist within a function, confusing the sorting.
>>        */
>> -    if (!sym->len)
>> +    if (sym->type == STT_NOTYPE && !sym->len)
>>           rb_erase(&sym->node, &sym->sec->symbol_tree);
>>   }
> 
> Is there a reason to do this, rather than change __WARN_FLAGS() to use 
> __builtin_unreachable()? Or, are you seeing an issue with unreachable() 
> elsewhere in the kernel?
> 

At the moment I'm trying to understand what the issue is, and explore 
possible fixes. I guess if we tell objtool that after 'twui' subsequent 
instructions are unreachable, then __builtin_unreachable() is enough.

I think we should also understand why annotate_unreachable() gives us a 
so bad result and see if it can be changed to something cleaner than a 
'bl' to an empty function that has no instructions.
Christophe Leroy June 30, 2022, 10:33 a.m. UTC | #8
Le 30/06/2022 à 11:58, Christophe Leroy a écrit :
> 
> 
> Le 30/06/2022 à 10:05, Naveen N. Rao a écrit :
>> Christophe Leroy wrote:
>>> Hi Sathvika,
>>>
>>> Adding ARM people as they seem to face the same kind of problem (see 
>>> https://patchwork.kernel.org/project/linux-kbuild/patch/20220623014917.199563-33-chenzhongjin@huawei.com/) 
>>>
>>>
>>> Le 27/06/2022 à 17:35, Sathvika Vasireddy a écrit :
>>>>
>>>> On 25/06/22 12:16, Christophe Leroy wrote:
>>>>>
>>>>> Le 24/06/2022 à 20:32, Sathvika Vasireddy a écrit :
>>>>>> objtool is throwing *unannotated intra-function call*
>>>>>> warnings with a few instructions that are marked
>>>>>> unreachable. Remove unreachable() from WARN_ON()
>>>>>> to fix these warnings, as the codegen remains same
>>>>>> with and without unreachable() in WARN_ON().
>>>>> Did you try the two exemples described in commit 1e688dd2a3d6
>>>>> ("powerpc/bug: Provide better flexibility to WARN_ON/__WARN_FLAGS() 
>>>>> with
>>>>> asm goto") ?
>>>>>
>>>>> Without your patch:
>>>>>
>>>>> 00000640 <test>:
>>>>>    640:    81 23 00 84     lwz     r9,132(r3)
>>>>>    644:    71 29 40 00     andi.   r9,r9,16384
>>>>>    648:    40 82 00 0c     bne     654 <test+0x14>
>>>>>    64c:    80 63 00 0c     lwz     r3,12(r3)
>>>>>    650:    4e 80 00 20     blr
>>>>>    654:    0f e0 00 00     twui    r0,0
>>>>>
>>>>> 00000658 <test9w>:
>>>>>    658:    2c 04 00 00     cmpwi   r4,0
>>>>>    65c:    41 82 00 0c     beq     668 <test9w+0x10>
>>>>>    660:    7c 63 23 96     divwu   r3,r3,r4
>>>>>    664:    4e 80 00 20     blr
>>>>>    668:    0f e0 00 00     twui    r0,0
>>>>>    66c:    38 60 00 00     li      r3,0
>>>>>    670:    4e 80 00 20     blr
>>>>>
>>>>>
>>>>> With your patch:
>>>>>
>>>>> 00000640 <test>:
>>>>>    640:    81 23 00 84     lwz     r9,132(r3)
>>>>>    644:    71 29 40 00     andi.   r9,r9,16384
>>>>>    648:    40 82 00 0c     bne     654 <test+0x14>
>>>>>    64c:    80 63 00 0c     lwz     r3,12(r3)
>>>>>    650:    4e 80 00 20     blr
>>>>>    654:    0f e0 00 00     twui    r0,0
>>>>>    658:    4b ff ff f4     b       64c <test+0xc>        <==
>>>>>
>>>>> 0000065c <test9w>:
>>>>>    65c:    2c 04 00 00     cmpwi   r4,0
>>>>>    660:    41 82 00 0c     beq     66c <test9w+0x10>
>>>>>    664:    7c 63 23 96     divwu   r3,r3,r4
>>>>>    668:    4e 80 00 20     blr
>>>>>    66c:    0f e0 00 00     twui    r0,0
>>>>>    670:    38 60 00 00     li      r3,0            <==
>>>>>    674:    4e 80 00 20     blr                <==
>>>>>    678:    38 60 00 00     li      r3,0
>>>>>    67c:    4e 80 00 20     blr
>>>>>
>>>> The builtin variant of unreachable (__builtin_unreachable()) works.
>>>>
>>>> How about using that instead of unreachable() ?
>>>>
>>>>
>>>
>>> In fact the problem comes from the macro annotate_unreachable() which 
>>> is called by unreachable() before calling __build_unreachable().
>>>
>>> Seems like this macro adds (after the unconditional trap twui) a call 
>>> to an empty function whose address is listed in section 
>>> .discard.unreachable
>>>
>>>      1c78:       00 00 e0 0f     twui    r0,0
>>>      1c7c:       55 e7 ff 4b     bl      3d0 
>>> <qdisc_root_sleeping_lock.part.0>
>>>
>>>
>>> RELOCATION RECORDS FOR [.discard.unreachable]:
>>> OFFSET           TYPE              VALUE
>>> 0000000000000000 R_PPC64_REL32     .text+0x00000000000003d0
>>>
>>> The problem is that that function has size 0:
>>>
>>> 00000000000003d0 l     F .text    0000000000000000 
>>> qdisc_root_sleeping_lock.part.0
>>>
>>>
>>> And objtool is not prepared for a function with size 0.
>>
>> annotate_unreachable() seems to have been introduced in commit 
>> 649ea4d5a624f0 ("objtool: Assume unannotated UD2 instructions are dead 
>> ends").
>>
>> Objtool considers 'ud2' instruction to be fatal, so BUG() has 
>> __builtin_unreachable(), rather than unreachable(). See commit 
>> bfb1a7c91fb775 ("x86/bug: Merge annotate_reachable() into _BUG_FLAGS() 
>> asm"). For the same reason, __WARN_FLAGS() is annotated with 
>> _ASM_REACHABLE so that objtool can differentiate warnings from a BUG().
>>
>> On powerpc, we use trap variants for both and don't have a special 
>> instruction for a BUG(). As such, for _WARN_FLAGS(), using 
>> __builtin_unreachable() suffices to achieve optimal code generation 
>> from the compiler. Objtool would consider subsequent instructions to 
>> be reachable. For BUG(), we can continue to use unreachable() so that 
>> objtool can differentiate these from traps used in warnings.
> 
> Not sure I understand what you mean.
> 
> __WARN_FLAGS() and BUG() both use 'twui' which is unconditionnal trap, 
> as such both are the same.
> 
> On the other side, WARN_ON() and BUG_ON() use tlbnei which is a 
> conditionnel trap.
> 
>>
>>>
>>> The following changes to objtool seem to fix the problem, most 
>>> warning are gone with that change.
>>>
>>> diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
>>> index 63218f5799c2..37c0a268b7ea 100644
>>> --- a/tools/objtool/elf.c
>>> +++ b/tools/objtool/elf.c
>>> @@ -77,6 +77,8 @@ static int symbol_by_offset(const void *key, const 
>>> struct rb_node *node)
>>>
>>>       if (*o < s->offset)
>>>           return -1;
>>> +    if (*o == s->offset && !s->len)
>>> +        return 0;
>>>       if (*o >= s->offset + s->len)
>>>           return 1;
>>>
>>> @@ -400,7 +402,7 @@ static void elf_add_symbol(struct elf *elf, 
>>> struct symbol *sym)
>>>        * Don't store empty STT_NOTYPE symbols in the rbtree.  They
>>>        * can exist within a function, confusing the sorting.
>>>        */
>>> -    if (!sym->len)
>>> +    if (sym->type == STT_NOTYPE && !sym->len)
>>>           rb_erase(&sym->node, &sym->sec->symbol_tree);
>>>   }
>>
>> Is there a reason to do this, rather than change __WARN_FLAGS() to use 
>> __builtin_unreachable()? Or, are you seeing an issue with 
>> unreachable() elsewhere in the kernel?
>>
> 
> At the moment I'm trying to understand what the issue is, and explore 
> possible fixes. I guess if we tell objtool that after 'twui' subsequent 
> instructions are unreachable, then __builtin_unreachable() is enough.

I get a nice result with the following changes (on top of Sathvika's 
series):

diff --git a/arch/powerpc/include/asm/bug.h b/arch/powerpc/include/asm/bug.h
index df6c11e008b9..73f5650f98df 100644
--- a/arch/powerpc/include/asm/bug.h
+++ b/arch/powerpc/include/asm/bug.h
@@ -89,7 +89,7 @@

  #define BUG() do {						\
  	BUG_ENTRY("twi 31, 0, 0", 0);				\
-	unreachable();						\
+	__builtin_unreachable();				\
  } while (0)
  #define HAVE_ARCH_BUG

@@ -97,6 +97,7 @@
  	__label__ __label_warn_on;				\
  								\
  	WARN_ENTRY("twi 31, 0, 0", BUGFLAG_WARNING | (flags), __label_warn_on); \
+	__builtin_unreachable();				\
  								\
  __label_warn_on:						\
  	break;							\
diff --git a/tools/objtool/arch/powerpc/decode.c 
b/tools/objtool/arch/powerpc/decode.c
index 06fc0206bf8e..9a0303304923 100644
--- a/tools/objtool/arch/powerpc/decode.c
+++ b/tools/objtool/arch/powerpc/decode.c
@@ -68,6 +68,8 @@ int arch_decode_instruction(struct objtool_file *file, 
const struct section *sec
  		}
  		break;
  	}
+	if (insn == 0x0fe00000) /* twui */
+		*type = INSN_BUG;

  	return 0;
  }
---

Christophe
Naveen N. Rao June 30, 2022, 10:37 a.m. UTC | #9
Christophe Leroy wrote:
> 
> 
> Le 30/06/2022 à 10:05, Naveen N. Rao a écrit :
>> Christophe Leroy wrote:
>>>> The builtin variant of unreachable (__builtin_unreachable()) works.
>>>>
>>>> How about using that instead of unreachable() ?
>>>>
>>>>
>>>
>>> In fact the problem comes from the macro annotate_unreachable() which 
>>> is called by unreachable() before calling __build_unreachable().
>>>
>>> Seems like this macro adds (after the unconditional trap twui) a call 
>>> to an empty function whose address is listed in section 
>>> .discard.unreachable
>>>
>>>      1c78:       00 00 e0 0f     twui    r0,0
>>>      1c7c:       55 e7 ff 4b     bl      3d0 
>>> <qdisc_root_sleeping_lock.part.0>
>>>
>>>
>>> RELOCATION RECORDS FOR [.discard.unreachable]:
>>> OFFSET           TYPE              VALUE
>>> 0000000000000000 R_PPC64_REL32     .text+0x00000000000003d0
>>>
>>> The problem is that that function has size 0:
>>>
>>> 00000000000003d0 l     F .text    0000000000000000 
>>> qdisc_root_sleeping_lock.part.0
>>>
>>>
>>> And objtool is not prepared for a function with size 0.
>> 
>> annotate_unreachable() seems to have been introduced in commit 
>> 649ea4d5a624f0 ("objtool: Assume unannotated UD2 instructions are dead 
>> ends").
>> 
>> Objtool considers 'ud2' instruction to be fatal, so BUG() has 
>> __builtin_unreachable(), rather than unreachable(). See commit 
>> bfb1a7c91fb775 ("x86/bug: Merge annotate_reachable() into _BUG_FLAGS() 
>> asm"). For the same reason, __WARN_FLAGS() is annotated with 
>> _ASM_REACHABLE so that objtool can differentiate warnings from a BUG().
>> 
>> On powerpc, we use trap variants for both and don't have a special 
>> instruction for a BUG(). As such, for _WARN_FLAGS(), using 
>> __builtin_unreachable() suffices to achieve optimal code generation from 
>> the compiler. Objtool would consider subsequent instructions to be 
>> reachable. For BUG(), we can continue to use unreachable() so that 
>> objtool can differentiate these from traps used in warnings.
> 
> Not sure I understand what you mean.
> 
> __WARN_FLAGS() and BUG() both use 'twui' which is unconditionnal trap, 
> as such both are the same.
> 
> On the other side, WARN_ON() and BUG_ON() use tlbnei which is a 
> conditionnel trap.

Objtool classifies 'ud2' as INSN_BUG, and 'int3' as INSN_TRAP. In x86 
BUG(), there is no need for an annotation since objtool assumes that 
'ud2' terminates control flow. But, for __WARN_FLAGS(), since 'ud2' is 
used, an explicit annotate_reachable() is needed. That's _reachable_, to 
indicate that the control flow can continue with the next instruction.

On powerpc, we should (eventually) classify all trap variants as 
INSN_TRAP. Even in the absence of that classification today, objtool 
assumes that control flow continues with the next instruction. With your 
work to utilize asm goto for __WARN_FLAGS(), with no extra instructions 
being generated, I think it is appropriate to just use 
__builtin_unreachable() and to not use the annotation.

In any case, we are only hitting this since gcc is generating a 'bl' due 
to that annotation. We are not yet enabling full objtool validation on 
powerpc, so I think we can revisit this at that point.

> 
>> 
>>>
>>> The following changes to objtool seem to fix the problem, most warning 
>>> are gone with that change.
>>>
>>> diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
>>> index 63218f5799c2..37c0a268b7ea 100644
>>> --- a/tools/objtool/elf.c
>>> +++ b/tools/objtool/elf.c
>>> @@ -77,6 +77,8 @@ static int symbol_by_offset(const void *key, const 
>>> struct rb_node *node)
>>>
>>>       if (*o < s->offset)
>>>           return -1;
>>> +    if (*o == s->offset && !s->len)
>>> +        return 0;
>>>       if (*o >= s->offset + s->len)
>>>           return 1;
>>>
>>> @@ -400,7 +402,7 @@ static void elf_add_symbol(struct elf *elf, struct 
>>> symbol *sym)
>>>        * Don't store empty STT_NOTYPE symbols in the rbtree.  They
>>>        * can exist within a function, confusing the sorting.
>>>        */
>>> -    if (!sym->len)
>>> +    if (sym->type == STT_NOTYPE && !sym->len)
>>>           rb_erase(&sym->node, &sym->sec->symbol_tree);
>>>   }
>> 
>> Is there a reason to do this, rather than change __WARN_FLAGS() to use 
>> __builtin_unreachable()? Or, are you seeing an issue with unreachable() 
>> elsewhere in the kernel?
>> 
> 
> At the moment I'm trying to understand what the issue is, and explore 
> possible fixes. I guess if we tell objtool that after 'twui' subsequent 
> instructions are unreachable, then __builtin_unreachable() is enough.

Yes, see my explanation above. Since no 'bl' is emitted with the 
builtin, objtool won't complain, especially for mcount.

> 
> I think we should also understand why annotate_unreachable() gives us a 
> so bad result and see if it can be changed to something cleaner than a 
> 'bl' to an empty function that has no instructions.

Indeed. Not really sure. annotate_unreachable() wants to take the 
address of the instruction after the trap. But, in reality, due to use 
of asm goto for __WARN_FLAGS, no instructions would be generated. I 
wonder if that combination causes such code to be emitted.


- Naveen
Segher Boessenkool June 30, 2022, 3:58 p.m. UTC | #10
On Thu, Jun 30, 2022 at 04:07:47PM +0530, Naveen N. Rao wrote:
> Objtool classifies 'ud2' as INSN_BUG, and 'int3' as INSN_TRAP. In x86 
> BUG(), there is no need for an annotation since objtool assumes that 
> 'ud2' terminates control flow. But, for __WARN_FLAGS(), since 'ud2' is 
> used, an explicit annotate_reachable() is needed. That's _reachable_, to 
> indicate that the control flow can continue with the next instruction.
> 
> On powerpc, we should (eventually) classify all trap variants as 
> INSN_TRAP. Even in the absence of that classification today, objtool 
> assumes that control flow continues with the next instruction. With your 
> work to utilize asm goto for __WARN_FLAGS(), with no extra instructions 
> being generated, I think it is appropriate to just use 
> __builtin_unreachable() and to not use the annotation.
> 
> In any case, we are only hitting this since gcc is generating a 'bl' due 
> to that annotation. We are not yet enabling full objtool validation on 
> powerpc, so I think we can revisit this at that point.

See also <https://gcc.gnu.org/PR99299> that asks for a __builtin_trap()
variant that does not terminate control flow ("that is recoverable").


Segher
Chen Zhongjin July 1, 2022, 2:13 a.m. UTC | #11
Hi everyone,

Hope I'm not too late for this discussion.

I'm not familiar with ppc so it spent me some time to reproduce this. 
But at last I didn't make it.

What I did:

1 checkout to tip/objtool/core

2 apply this patch

3 recover the unreachable() after WARN_ENTRY(..

4 compile on defconfig/allyesconfig

If anyone can point out which file will generate this problem it will be 
perfect.

On 2022/6/30 16:05, Naveen N. Rao wrote:
> Christophe Leroy wrote:
>> Hi Sathvika,
>>
>> Adding ARM people as they seem to face the same kind of problem (see 
>> https://patchwork.kernel.org/project/linux-kbuild/patch/20220623014917.199563-33-chenzhongjin@huawei.com/)

For my situation, the problem is, if there is an unreachable() used in 
the switch default case with nothing else, compiler will generate a NOP 
and is still a jump to this NOP branch while it is marked in 
.discard.unreachable.

When objtool deal with .discard.unreachable, it will *do nothing* to 
this NOP itself, but mark the previous instruction as "dead_end" (see 
check.c:ignore_unreachable_insn()). And checking will stop when reach 
this dead_end insn.

0x4: jne 0x14        <= jump for switch case

..

0x10: ret                <= dead_end

0x14: nop              <= real unreachable instructiond

However, actually we have a jump to NOP, which makes this reachable to 
this branch, and when this NOP is at end of function, it get a "fall 
through" warning.


I changed the unreachable to -EINVAL but it was criticized by the 
committer because he thought it is objtool's job to deal with these 
special cases.

>>
>> Le 27/06/2022 à 17:35, Sathvika Vasireddy a écrit :
>>>
>>> On 25/06/22 12:16, Christophe Leroy wrote:
>>>>
>>>> Le 24/06/2022 à 20:32, Sathvika Vasireddy a écrit :
>>>>> objtool is throwing *unannotated intra-function call*
>>>>> warnings with a few instructions that are marked
>>>>> unreachable. Remove unreachable() from WARN_ON()
>>>>> to fix these warnings, as the codegen remains same
>>>>> with and without unreachable() in WARN_ON().
>>>> Did you try the two exemples described in commit 1e688dd2a3d6
>>>> ("powerpc/bug: Provide better flexibility to WARN_ON/__WARN_FLAGS() 
>>>> with
>>>> asm goto") ?
>>>>
>>>> Without your patch:
>>>>
>>>> 00000640 <test>:
>>>>    640:    81 23 00 84     lwz     r9,132(r3)
>>>>    644:    71 29 40 00     andi.   r9,r9,16384
>>>>    648:    40 82 00 0c     bne     654 <test+0x14>
>>>>    64c:    80 63 00 0c     lwz     r3,12(r3)
>>>>    650:    4e 80 00 20     blr
>>>>    654:    0f e0 00 00     twui    r0,0
>>>>
>>>> 00000658 <test9w>:
>>>>    658:    2c 04 00 00     cmpwi   r4,0
>>>>    65c:    41 82 00 0c     beq     668 <test9w+0x10>
>>>>    660:    7c 63 23 96     divwu   r3,r3,r4
>>>>    664:    4e 80 00 20     blr
>>>>    668:    0f e0 00 00     twui    r0,0
>>>>    66c:    38 60 00 00     li      r3,0
>>>>    670:    4e 80 00 20     blr
>>>>
>>>>
>>>> With your patch:
>>>>
>>>> 00000640 <test>:
>>>>    640:    81 23 00 84     lwz     r9,132(r3)
>>>>    644:    71 29 40 00     andi.   r9,r9,16384
>>>>    648:    40 82 00 0c     bne     654 <test+0x14>
>>>>    64c:    80 63 00 0c     lwz     r3,12(r3)
>>>>    650:    4e 80 00 20     blr
>>>>    654:    0f e0 00 00     twui    r0,0
>>>>    658:    4b ff ff f4     b       64c <test+0xc>        <==
>>>>
>>>> 0000065c <test9w>:
>>>>    65c:    2c 04 00 00     cmpwi   r4,0
>>>>    660:    41 82 00 0c     beq     66c <test9w+0x10>
>>>>    664:    7c 63 23 96     divwu   r3,r3,r4
>>>>    668:    4e 80 00 20     blr
>>>>    66c:    0f e0 00 00     twui    r0,0
>>>>    670:    38 60 00 00     li      r3,0            <==
>>>>    674:    4e 80 00 20     blr                <==
>>>>    678:    38 60 00 00     li      r3,0
>>>>    67c:    4e 80 00 20     blr
>>>>
>>> The builtin variant of unreachable (__builtin_unreachable()) works.
>>>
>>> How about using that instead of unreachable() ?
>>>
>>>
>>
>> In fact the problem comes from the macro annotate_unreachable() which 
>> is called by unreachable() before calling __build_unreachable().
>>
>> Seems like this macro adds (after the unconditional trap twui) a call 
>> to an empty function whose address is listed in section 
>> .discard.unreachable
>>
>>      1c78:       00 00 e0 0f     twui    r0,0
>>      1c7c:       55 e7 ff 4b     bl      3d0 
>> <qdisc_root_sleeping_lock.part.0>
>>
>>
>> RELOCATION RECORDS FOR [.discard.unreachable]:
>> OFFSET           TYPE              VALUE
>> 0000000000000000 R_PPC64_REL32     .text+0x00000000000003d0
>>
>> The problem is that that function has size 0:
>>
>> 00000000000003d0 l     F .text    0000000000000000 
>> qdisc_root_sleeping_lock.part.0
>>
>>
>> And objtool is not prepared for a function with size 0.
>
> annotate_unreachable() seems to have been introduced in commit 
> 649ea4d5a624f0 ("objtool: Assume unannotated UD2 instructions are dead 
> ends").
>
> Objtool considers 'ud2' instruction to be fatal, so BUG() has 
> __builtin_unreachable(), rather than unreachable(). See commit 
> bfb1a7c91fb775 ("x86/bug: Merge annotate_reachable() into _BUG_FLAGS() 
> asm"). For the same reason, __WARN_FLAGS() is annotated with 
> _ASM_REACHABLE so that objtool can differentiate warnings from a BUG().
>
> On powerpc, we use trap variants for both and don't have a special 
> instruction for a BUG(). As such, for _WARN_FLAGS(), using 
> __builtin_unreachable() suffices to achieve optimal code generation 
> from the compiler. Objtool would consider subsequent instructions to 
> be reachable. For BUG(), we can continue to use unreachable() so that 
> objtool can differentiate these from traps used in warnings.
>
It is right and on arm64 only BUG() has unreachable and there is no 
annotation for __WARN_FLAGS(). Objtool works correctly on this. For that 
I support that unreachable() annotation shouldn't be with __WARN_FLAGS() 
because there should be an accessible branch after WARN() micro. However 
in the previous case, it's wired that compiler generates a bl to 
unreachable symbol, IIUC it is not a illegal call? (if it is allowed on 
ppc then objtool should be tell to recognize this)


It seems that your decoding only care about INSN_CALL for mcount, so 
maybe temporarily these control flow checking makes non-sense for you so 
the solution could actually be looser.

Anyway, maybe I can help more if I can reproduce that on my own machine.


Best,

Chen

.
Sathvika Vasireddy July 1, 2022, 6:56 a.m. UTC | #12
Hi Chen,

Thanks for pitching in and providing your inputs :-)

On 01/07/22 07:43, Chen Zhongjin wrote:
> Hi everyone,
>
> Hope I'm not too late for this discussion.
>
> I'm not familiar with ppc so it spent me some time to reproduce this. 
> But at last I didn't make it.
>
> What I did:
>
> 1 checkout to tip/objtool/core
>
> 2 apply this patch
>
> 3 recover the unreachable() after WARN_ENTRY(..
>
> 4 compile on defconfig/allyesconfig
>
> If anyone can point out which file will generate this problem it will 
> be perfect.

To reproduce this problem, you may want to apply this patch series on 
top of objtool/core branch of the tip tree, and compile on 
ppc64le_defconfig.

There are a couple of C files that are generating these warnings. One 
such file is: arch/powerpc/kvm/../../../virt/kvm/kvm_main.o which gives
*arch/powerpc/kvm/../../../virt/kvm/kvm_main.o: warning: objtool: 
kvm_mmu_notifier_release+0x6c: unannotated intra-function call* warning.

With unreachable() in __WARN_FLAGS(), we get unannotated intra-function 
call warnings, but without unreachable() like in patch 11/12 or with 
just the builtin variant of unreachable (__builtin_unreachable()) 
instead of unreachable(), we do not get those warnings.


- Sathvika
Christophe Leroy July 1, 2022, 11:40 a.m. UTC | #13
Hi Segher, your help might be welcome,

Le 01/07/2022 à 08:56, Sathvika Vasireddy a écrit :
> Hi Chen,
> 
> Thanks for pitching in and providing your inputs :-)
> 
> On 01/07/22 07:43, Chen Zhongjin wrote:
>> Hi everyone,
>>
>> Hope I'm not too late for this discussion.
>>
>> I'm not familiar with ppc so it spent me some time to reproduce this. 
>> But at last I didn't make it.
>>
>> What I did:
>>
>> 1 checkout to tip/objtool/core
>>
>> 2 apply this patch
>>
>> 3 recover the unreachable() after WARN_ENTRY(..
>>
>> 4 compile on defconfig/allyesconfig
>>
>> If anyone can point out which file will generate this problem it will 
>> be perfect.
> 
> To reproduce this problem, you may want to apply this patch series on 
> top of objtool/core branch of the tip tree, and compile on 
> ppc64le_defconfig.
> 
> There are a couple of C files that are generating these warnings. One 
> such file is: arch/powerpc/kvm/../../../virt/kvm/kvm_main.o which gives
> *arch/powerpc/kvm/../../../virt/kvm/kvm_main.o: warning: objtool: 
> kvm_mmu_notifier_release+0x6c: unannotated intra-function call* warning.
> 
> With unreachable() in __WARN_FLAGS(), we get unannotated intra-function 
> call warnings, but without unreachable() like in patch 11/12 or with 
> just the builtin variant of unreachable (__builtin_unreachable()) 
> instead of unreachable(), we do not get those warnings.
> 


I made a simple test aside our issue to see if I get something similar 
to ARM. I don't if it is the same at the end, but it looks odd anyway:

int test(int x)
{
	switch(x) {
	case 0 : return 3;
	case 1 : return 5;
	default : unreachable();
	}
}

0000000000001c80 <test>:
     1c80:       a6 02 08 7c     mflr    r0
     1c84:       01 00 00 48     bl      1c84 <test+0x4>
                         1c84: R_PPC64_REL24     _mcount
     1c88:       00 00 23 2c     cmpdi   r3,0
     1c8c:       14 00 82 41     beq     1ca0 <test+0x20>
     1c90:       01 00 03 2c     cmpwi   r3,1
     1c94:       05 00 60 38     li      r3,5
     1c98:       20 00 82 4d     beqlr
     1c9c:       00 00 42 60     ori     r2,r2,0
     1ca0:       03 00 60 38     li      r3,3
     1ca4:       20 00 80 4e     blr

So it looks like it takes no real benefit from the unreachable marking.

Now with __builtin_unreachable() instead of unreachable() :

int test(int x)
{
	switch(x) {
	case 0 : return 3;
	case 1 : return 5;
	default : __builtin_unreachable();
	}
}

0000000000001c80 <test>:
     1c80:       a6 02 08 7c     mflr    r0
     1c84:       01 00 00 48     bl      1c84 <test+0x4>
                         1c84: R_PPC64_REL24     _mcount
     1c88:       00 00 63 20     subfic  r3,r3,0
     1c8c:       10 19 63 7c     subfe   r3,r3,r3
     1c90:       bc 07 63 54     rlwinm  r3,r3,0,30,30
     1c94:       03 00 63 38     addi    r3,r3,3
     1c98:       20 00 80 4e     blr


Here the generated code takes advantage of the unreachable marking and 
results in a branchless code.


Christophe
Peter Zijlstra July 4, 2022, 11:43 a.m. UTC | #14
On Thu, Jun 30, 2022 at 04:07:47PM +0530, Naveen N. Rao wrote:

> Objtool classifies 'ud2' as INSN_BUG, and 'int3' as INSN_TRAP. In x86 BUG(),

Yes, ud2 is the traditional 'kill' instruction and a number of emulators
treat it as such, however it also being the shortest encoding (2 bytes)
for #UD Linux has opted to (ab)use it to implement WARN/BUG.

As such interpretation of 'ud2' needs to assume control flow stops
(compiler will also emit ud2 in a number of cases with that intent).
However, if it's used as WARN we then need to annotate the thing to not
be terminal.

> there is no need for an annotation since objtool assumes that 'ud2'
> terminates control flow. But, for __WARN_FLAGS(), since 'ud2' is used, an
> explicit annotate_reachable() is needed. That's _reachable_, to indicate
> that the control flow can continue with the next instruction.
> 
> On powerpc, we should (eventually) classify all trap variants as INSN_TRAP.

Careful.. INSN_TRAP is mostly used for purposes of speculation stop and
padding. That is, INSN_TRAP does indeed not affect control flow, but the
way objtool treats it might not be quite what you want.

Specifically, straight-line-speculation checks want INT3 after indirect
control transfers (indirect jump and return -- indirect call is
'difficult'); these locations are architecturally not executed and as
such placing a random trap instruction there is 'harmless'. Of course,
were the branch predictor to go wobbly and attempt to execute it, the
fact that it's a trap will stop speculation dead.

Additionally, int3, being a single byte instruction, is also used to
fill dead code space, any #BP trap on it will not have a descriptor and
mostly cause the kernel to go splat.

Per the last usage, validate_reachable_instructions() will ignore it.
I'm not sure you want to always ignore all your (unreachable) trap
instructions.
Peter Zijlstra July 4, 2022, 11:45 a.m. UTC | #15
On Wed, Jun 29, 2022 at 06:30:23PM +0000, Christophe Leroy wrote:


> The problem is that that function has size 0:
> 
> 00000000000003d0 l     F .text	0000000000000000 
> qdisc_root_sleeping_lock.part.0

I'm somewhat confused; how is an empty STT_FUNC a valid construct on
Power?
Peter Zijlstra July 4, 2022, 12:01 p.m. UTC | #16
On Thu, Jun 30, 2022 at 10:58:11AM -0500, Segher Boessenkool wrote:
> On Thu, Jun 30, 2022 at 04:07:47PM +0530, Naveen N. Rao wrote:
> > Objtool classifies 'ud2' as INSN_BUG, and 'int3' as INSN_TRAP. In x86 
> > BUG(), there is no need for an annotation since objtool assumes that 
> > 'ud2' terminates control flow. But, for __WARN_FLAGS(), since 'ud2' is 
> > used, an explicit annotate_reachable() is needed. That's _reachable_, to 
> > indicate that the control flow can continue with the next instruction.
> > 
> > On powerpc, we should (eventually) classify all trap variants as 
> > INSN_TRAP. Even in the absence of that classification today, objtool 
> > assumes that control flow continues with the next instruction. With your 
> > work to utilize asm goto for __WARN_FLAGS(), with no extra instructions 
> > being generated, I think it is appropriate to just use 
> > __builtin_unreachable() and to not use the annotation.
> > 
> > In any case, we are only hitting this since gcc is generating a 'bl' due 
> > to that annotation. We are not yet enabling full objtool validation on 
> > powerpc, so I think we can revisit this at that point.
> 
> See also <https://gcc.gnu.org/PR99299> that asks for a __builtin_trap()
> variant that does not terminate control flow ("that is recoverable").

Re comment 9 there, x86 must assume ud2 will abort. If the compiler were
to emit ud2 for non-abort purposes then it needs to somehow annotate
this so that both objtool and the kernel can determine this.

That said; the whole annotate_reachable() thing in our WARN is
superfluous, we should read __bug_table instead. That said, we still
need _ASM_REACHABLE to handle a few noreturn cases, so there is no real
pressing reason to go clean that up. (if only the compiler would tell us
about noreturn)

ARM has an immediate in their break instruction and varies the desired
behaviour depending on the immediate.
Peter Zijlstra July 4, 2022, 12:05 p.m. UTC | #17
On Sat, Jun 25, 2022 at 06:46:54AM +0000, Christophe Leroy wrote:
> 
> 
> Le 24/06/2022 à 20:32, Sathvika Vasireddy a écrit :
> > objtool is throwing *unannotated intra-function call*
> > warnings with a few instructions that are marked
> > unreachable. Remove unreachable() from WARN_ON()
> > to fix these warnings, as the codegen remains same
> > with and without unreachable() in WARN_ON().
> 
> Did you try the two exemples described in commit 1e688dd2a3d6 
> ("powerpc/bug: Provide better flexibility to WARN_ON/__WARN_FLAGS() with 
> asm goto") ?
> 
> Without your patch:
> 
> 00000640 <test>:
>   640:	81 23 00 84 	lwz     r9,132(r3)
>   644:	71 29 40 00 	andi.   r9,r9,16384
>   648:	40 82 00 0c 	bne     654 <test+0x14>
>   64c:	80 63 00 0c 	lwz     r3,12(r3)
>   650:	4e 80 00 20 	blr
>   654:	0f e0 00 00 	twui    r0,0
> 
> 00000658 <test9w>:
>   658:	2c 04 00 00 	cmpwi   r4,0
>   65c:	41 82 00 0c 	beq     668 <test9w+0x10>
>   660:	7c 63 23 96 	divwu   r3,r3,r4
>   664:	4e 80 00 20 	blr
>   668:	0f e0 00 00 	twui    r0,0
>   66c:	38 60 00 00 	li      r3,0
>   670:	4e 80 00 20 	blr

Per this construct you should do as x86 does and assume twui terminates
control flow and explicitly annotate the WARN case. That is, given the
fact that BUG as no instructions following it, you can't very well
annotate that.

Alternatively, you can teach objtool to look at __bug_table to
distinguish these cases.
Christophe Leroy July 4, 2022, 12:34 p.m. UTC | #18
Le 04/07/2022 à 13:45, Peter Zijlstra a écrit :
> On Wed, Jun 29, 2022 at 06:30:23PM +0000, Christophe Leroy wrote:
> 
> 
>> The problem is that that function has size 0:
>>
>> 00000000000003d0 l     F .text	0000000000000000
>> qdisc_root_sleeping_lock.part.0
> 
> I'm somewhat confused; how is an empty STT_FUNC a valid construct on
> Power?

So am I. It is likely not a valid construct, but that's what GCC seems 
to generate when you call annotate_unreachable().
Christophe Leroy July 4, 2022, 12:44 p.m. UTC | #19
Le 04/07/2022 à 14:05, Peter Zijlstra a écrit :
> On Sat, Jun 25, 2022 at 06:46:54AM +0000, Christophe Leroy wrote:
>>
>>
>> Le 24/06/2022 à 20:32, Sathvika Vasireddy a écrit :
>>> objtool is throwing *unannotated intra-function call*
>>> warnings with a few instructions that are marked
>>> unreachable. Remove unreachable() from WARN_ON()
>>> to fix these warnings, as the codegen remains same
>>> with and without unreachable() in WARN_ON().
>>
>> Did you try the two exemples described in commit 1e688dd2a3d6
>> ("powerpc/bug: Provide better flexibility to WARN_ON/__WARN_FLAGS() with
>> asm goto") ?
>>
>> Without your patch:
>>
>> 00000640 <test>:
>>    640:	81 23 00 84 	lwz     r9,132(r3)
>>    644:	71 29 40 00 	andi.   r9,r9,16384
>>    648:	40 82 00 0c 	bne     654 <test+0x14>
>>    64c:	80 63 00 0c 	lwz     r3,12(r3)
>>    650:	4e 80 00 20 	blr
>>    654:	0f e0 00 00 	twui    r0,0
>>
>> 00000658 <test9w>:
>>    658:	2c 04 00 00 	cmpwi   r4,0
>>    65c:	41 82 00 0c 	beq     668 <test9w+0x10>
>>    660:	7c 63 23 96 	divwu   r3,r3,r4
>>    664:	4e 80 00 20 	blr
>>    668:	0f e0 00 00 	twui    r0,0
>>    66c:	38 60 00 00 	li      r3,0
>>    670:	4e 80 00 20 	blr
> 
> Per this construct you should do as x86 does and assume twui terminates
> control flow and explicitly annotate the WARN case. That is, given the
> fact that BUG as no instructions following it, you can't very well
> annotate that.

That exactly the problem I guess. I'm fine with replacing the 
unreachable() by __builtin_unreachable() with our __WARN_FLAGS() and 
BUG() but we will still have a problem with some of the unrachable() 
that are in core parts of the kernel.

Even the ones in arch/powerpc/, they are valid and should remain. The 
point seems that the generic annotate_unreachable() is wrong for powerpc 
as is, and activating CONFIG_OBJTOOL lead to bad code generation.

By the way, for which functionnalities of objtool is that analysis 
necessary ? I understand it is not necessary to mcount accounting, so 
maybe the not empty annotate_unreachable() should be limited to those 
those functionnalities ?

> 
> Alternatively, you can teach objtool to look at __bug_table to
> distinguish these cases.

Isn't it enough to tell objtool that execution never go past twui, using 
INSN_BUG ?
By the way, for __WARN_FLAGS, we use the __extable for the continuation. 
Is objtools able to follow __extable ?

Christophe
Peter Zijlstra July 4, 2022, 2:19 p.m. UTC | #20
On Mon, Jul 04, 2022 at 12:44:30PM +0000, Christophe Leroy wrote:
> 
> 
> Le 04/07/2022 à 14:05, Peter Zijlstra a écrit :
> > On Sat, Jun 25, 2022 at 06:46:54AM +0000, Christophe Leroy wrote:
> >>
> >>
> >> Le 24/06/2022 à 20:32, Sathvika Vasireddy a écrit :
> >>> objtool is throwing *unannotated intra-function call*
> >>> warnings with a few instructions that are marked
> >>> unreachable. Remove unreachable() from WARN_ON()
> >>> to fix these warnings, as the codegen remains same
> >>> with and without unreachable() in WARN_ON().
> >>
> >> Did you try the two exemples described in commit 1e688dd2a3d6
> >> ("powerpc/bug: Provide better flexibility to WARN_ON/__WARN_FLAGS() with
> >> asm goto") ?
> >>
> >> Without your patch:
> >>
> >> 00000640 <test>:
> >>    640:	81 23 00 84 	lwz     r9,132(r3)
> >>    644:	71 29 40 00 	andi.   r9,r9,16384
> >>    648:	40 82 00 0c 	bne     654 <test+0x14>
> >>    64c:	80 63 00 0c 	lwz     r3,12(r3)
> >>    650:	4e 80 00 20 	blr
> >>    654:	0f e0 00 00 	twui    r0,0
> >>
> >> 00000658 <test9w>:
> >>    658:	2c 04 00 00 	cmpwi   r4,0
> >>    65c:	41 82 00 0c 	beq     668 <test9w+0x10>
> >>    660:	7c 63 23 96 	divwu   r3,r3,r4
> >>    664:	4e 80 00 20 	blr
> >>    668:	0f e0 00 00 	twui    r0,0
> >>    66c:	38 60 00 00 	li      r3,0
> >>    670:	4e 80 00 20 	blr
> > 
> > Per this construct you should do as x86 does and assume twui terminates
> > control flow and explicitly annotate the WARN case. That is, given the
> > fact that BUG as no instructions following it, you can't very well
> > annotate that.
> 
> That exactly the problem I guess. I'm fine with replacing the 
> unreachable() by __builtin_unreachable() with our __WARN_FLAGS() and 
> BUG() but we will still have a problem with some of the unrachable() 
> that are in core parts of the kernel.
> 
> Even the ones in arch/powerpc/, they are valid and should remain. The 
> point seems that the generic annotate_unreachable() is wrong for powerpc 
> as is, and activating CONFIG_OBJTOOL lead to bad code generation.

Right; I'm not against making that depend on yet-another OBJTOOL_$config
thing.

> By the way, for which functionnalities of objtool is that analysis 
> necessary ? I understand it is not necessary to mcount accounting, so 
> maybe the not empty annotate_unreachable() should be limited to those 
> those functionnalities ?

For all the things where it needs to follow control flow, so stack
validation, ORC generation, unreachable instruction validation etc..

I'd need to double check code-gen on x86, but the way
__builtin_unreachable() makes code-gen stop dead, I'm not entirely sure
it's right for us either.

> > Alternatively, you can teach objtool to look at __bug_table to
> > distinguish these cases.
> 
> Isn't it enough to tell objtool that execution never go past twui, using 
> INSN_BUG ?

That should work I suppose.

> By the way, for __WARN_FLAGS, we use the __extable for the continuation. 
> Is objtools able to follow __extable ?

Yes.
Segher Boessenkool July 5, 2022, 3:48 p.m. UTC | #21
On Mon, Jul 04, 2022 at 12:34:08PM +0000, Christophe Leroy wrote:
> Le 04/07/2022 à 13:45, Peter Zijlstra a écrit :
> > I'm somewhat confused; how is an empty STT_FUNC a valid construct on
> > Power?
> 
> So am I. It is likely not a valid construct, but that's what GCC seems 
> to generate when you call annotate_unreachable().

It is a valid construct on (almost) all targets.  If the user chooses to
have executable code terminate in limbo, that is what the compiler will
do (and this can result in a code symbol with size 0).  Compare this to
data symbols with no size, the situation is quite similar.


Segher
diff mbox series

Patch

diff --git a/arch/powerpc/include/asm/bug.h b/arch/powerpc/include/asm/bug.h
index ecbae1832de3..df6c11e008b9 100644
--- a/arch/powerpc/include/asm/bug.h
+++ b/arch/powerpc/include/asm/bug.h
@@ -97,7 +97,6 @@ 
 	__label__ __label_warn_on;				\
 								\
 	WARN_ENTRY("twi 31, 0, 0", BUGFLAG_WARNING | (flags), __label_warn_on); \
-	unreachable();						\
 								\
 __label_warn_on:						\
 	break;							\