@@ -338,6 +338,12 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start,
338338 }
339339}
340340
341+ static inline bool is_jcc32 (struct insn * insn )
342+ {
343+ /* Jcc.d32 second opcode byte is in the range: 0x80-0x8f */
344+ return insn -> opcode .bytes [0 ] == 0x0f && (insn -> opcode .bytes [1 ] & 0xf0 ) == 0x80 ;
345+ }
346+
341347#if defined(CONFIG_RETPOLINE ) && defined(CONFIG_OBJTOOL )
342348
343349/*
@@ -376,12 +382,6 @@ static int emit_indirect(int op, int reg, u8 *bytes)
376382 return i ;
377383}
378384
379- static inline bool is_jcc32 (struct insn * insn )
380- {
381- /* Jcc.d32 second opcode byte is in the range: 0x80-0x8f */
382- return insn -> opcode .bytes [0 ] == 0x0f && (insn -> opcode .bytes [1 ] & 0xf0 ) == 0x80 ;
383- }
384-
385385static int emit_call_track_retpoline (void * addr , struct insn * insn , int reg , u8 * bytes )
386386{
387387 u8 op = insn -> opcode .bytes [0 ];
@@ -1770,6 +1770,11 @@ void text_poke_sync(void)
17701770 on_each_cpu (do_sync_core , NULL , 1 );
17711771}
17721772
1773+ /*
1774+ * NOTE: crazy scheme to allow patching Jcc.d32 but not increase the size of
1775+ * this thing. When len == 6 everything is prefixed with 0x0f and we map
1776+ * opcode to Jcc.d8, using len to distinguish.
1777+ */
17731778struct text_poke_loc {
17741779 /* addr := _stext + rel_addr */
17751780 s32 rel_addr ;
@@ -1891,6 +1896,10 @@ noinstr int poke_int3_handler(struct pt_regs *regs)
18911896 int3_emulate_jmp (regs , (long )ip + tp -> disp );
18921897 break ;
18931898
1899+ case 0x70 ... 0x7f : /* Jcc */
1900+ int3_emulate_jcc (regs , tp -> opcode & 0xf , (long )ip , tp -> disp );
1901+ break ;
1902+
18941903 default :
18951904 BUG ();
18961905 }
@@ -1964,16 +1973,26 @@ static void text_poke_bp_batch(struct text_poke_loc *tp, unsigned int nr_entries
19641973 * Second step: update all but the first byte of the patched range.
19651974 */
19661975 for (do_sync = 0 , i = 0 ; i < nr_entries ; i ++ ) {
1967- u8 old [POKE_MAX_OPCODE_SIZE ] = { tp [i ].old , };
1976+ u8 old [POKE_MAX_OPCODE_SIZE + 1 ] = { tp [i ].old , };
1977+ u8 _new [POKE_MAX_OPCODE_SIZE + 1 ];
1978+ const u8 * new = tp [i ].text ;
19681979 int len = tp [i ].len ;
19691980
19701981 if (len - INT3_INSN_SIZE > 0 ) {
19711982 memcpy (old + INT3_INSN_SIZE ,
19721983 text_poke_addr (& tp [i ]) + INT3_INSN_SIZE ,
19731984 len - INT3_INSN_SIZE );
1985+
1986+ if (len == 6 ) {
1987+ _new [0 ] = 0x0f ;
1988+ memcpy (_new + 1 , new , 5 );
1989+ new = _new ;
1990+ }
1991+
19741992 text_poke (text_poke_addr (& tp [i ]) + INT3_INSN_SIZE ,
1975- ( const char * ) tp [ i ]. text + INT3_INSN_SIZE ,
1993+ new + INT3_INSN_SIZE ,
19761994 len - INT3_INSN_SIZE );
1995+
19771996 do_sync ++ ;
19781997 }
19791998
@@ -2001,8 +2020,7 @@ static void text_poke_bp_batch(struct text_poke_loc *tp, unsigned int nr_entries
20012020 * The old instruction is recorded so that the event can be
20022021 * processed forwards or backwards.
20032022 */
2004- perf_event_text_poke (text_poke_addr (& tp [i ]), old , len ,
2005- tp [i ].text , len );
2023+ perf_event_text_poke (text_poke_addr (& tp [i ]), old , len , new , len );
20062024 }
20072025
20082026 if (do_sync ) {
@@ -2019,10 +2037,15 @@ static void text_poke_bp_batch(struct text_poke_loc *tp, unsigned int nr_entries
20192037 * replacing opcode.
20202038 */
20212039 for (do_sync = 0 , i = 0 ; i < nr_entries ; i ++ ) {
2022- if (tp [i ].text [0 ] == INT3_INSN_OPCODE )
2040+ u8 byte = tp [i ].text [0 ];
2041+
2042+ if (tp [i ].len == 6 )
2043+ byte = 0x0f ;
2044+
2045+ if (byte == INT3_INSN_OPCODE )
20232046 continue ;
20242047
2025- text_poke (text_poke_addr (& tp [i ]), tp [ i ]. text , INT3_INSN_SIZE );
2048+ text_poke (text_poke_addr (& tp [i ]), & byte , INT3_INSN_SIZE );
20262049 do_sync ++ ;
20272050 }
20282051
@@ -2040,9 +2063,11 @@ static void text_poke_loc_init(struct text_poke_loc *tp, void *addr,
20402063 const void * opcode , size_t len , const void * emulate )
20412064{
20422065 struct insn insn ;
2043- int ret , i ;
2066+ int ret , i = 0 ;
20442067
2045- memcpy ((void * )tp -> text , opcode , len );
2068+ if (len == 6 )
2069+ i = 1 ;
2070+ memcpy ((void * )tp -> text , opcode + i , len - i );
20462071 if (!emulate )
20472072 emulate = opcode ;
20482073
@@ -2053,6 +2078,13 @@ static void text_poke_loc_init(struct text_poke_loc *tp, void *addr,
20532078 tp -> len = len ;
20542079 tp -> opcode = insn .opcode .bytes [0 ];
20552080
2081+ if (is_jcc32 (& insn )) {
2082+ /*
2083+ * Map Jcc.d32 onto Jcc.d8 and use len to distinguish.
2084+ */
2085+ tp -> opcode = insn .opcode .bytes [1 ] - 0x10 ;
2086+ }
2087+
20562088 switch (tp -> opcode ) {
20572089 case RET_INSN_OPCODE :
20582090 case JMP32_INSN_OPCODE :
@@ -2069,7 +2101,6 @@ static void text_poke_loc_init(struct text_poke_loc *tp, void *addr,
20692101 BUG_ON (len != insn .length );
20702102 }
20712103
2072-
20732104 switch (tp -> opcode ) {
20742105 case INT3_INSN_OPCODE :
20752106 case RET_INSN_OPCODE :
@@ -2078,6 +2109,7 @@ static void text_poke_loc_init(struct text_poke_loc *tp, void *addr,
20782109 case CALL_INSN_OPCODE :
20792110 case JMP32_INSN_OPCODE :
20802111 case JMP8_INSN_OPCODE :
2112+ case 0x70 ... 0x7f : /* Jcc */
20812113 tp -> disp = insn .immediate .value ;
20822114 break ;
20832115
0 commit comments