@@ -338,6 +338,12 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start,
338
338
}
339
339
}
340
340
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
+
341
347
#if defined(CONFIG_RETPOLINE ) && defined(CONFIG_OBJTOOL )
342
348
343
349
/*
@@ -376,12 +382,6 @@ static int emit_indirect(int op, int reg, u8 *bytes)
376
382
return i ;
377
383
}
378
384
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
-
385
385
static int emit_call_track_retpoline (void * addr , struct insn * insn , int reg , u8 * bytes )
386
386
{
387
387
u8 op = insn -> opcode .bytes [0 ];
@@ -1770,6 +1770,11 @@ void text_poke_sync(void)
1770
1770
on_each_cpu (do_sync_core , NULL , 1 );
1771
1771
}
1772
1772
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
+ */
1773
1778
struct text_poke_loc {
1774
1779
/* addr := _stext + rel_addr */
1775
1780
s32 rel_addr ;
@@ -1891,6 +1896,10 @@ noinstr int poke_int3_handler(struct pt_regs *regs)
1891
1896
int3_emulate_jmp (regs , (long )ip + tp -> disp );
1892
1897
break ;
1893
1898
1899
+ case 0x70 ... 0x7f : /* Jcc */
1900
+ int3_emulate_jcc (regs , tp -> opcode & 0xf , (long )ip , tp -> disp );
1901
+ break ;
1902
+
1894
1903
default :
1895
1904
BUG ();
1896
1905
}
@@ -1964,16 +1973,26 @@ static void text_poke_bp_batch(struct text_poke_loc *tp, unsigned int nr_entries
1964
1973
* Second step: update all but the first byte of the patched range.
1965
1974
*/
1966
1975
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 ;
1968
1979
int len = tp [i ].len ;
1969
1980
1970
1981
if (len - INT3_INSN_SIZE > 0 ) {
1971
1982
memcpy (old + INT3_INSN_SIZE ,
1972
1983
text_poke_addr (& tp [i ]) + INT3_INSN_SIZE ,
1973
1984
len - INT3_INSN_SIZE );
1985
+
1986
+ if (len == 6 ) {
1987
+ _new [0 ] = 0x0f ;
1988
+ memcpy (_new + 1 , new , 5 );
1989
+ new = _new ;
1990
+ }
1991
+
1974
1992
text_poke (text_poke_addr (& tp [i ]) + INT3_INSN_SIZE ,
1975
- ( const char * ) tp [ i ]. text + INT3_INSN_SIZE ,
1993
+ new + INT3_INSN_SIZE ,
1976
1994
len - INT3_INSN_SIZE );
1995
+
1977
1996
do_sync ++ ;
1978
1997
}
1979
1998
@@ -2001,8 +2020,7 @@ static void text_poke_bp_batch(struct text_poke_loc *tp, unsigned int nr_entries
2001
2020
* The old instruction is recorded so that the event can be
2002
2021
* processed forwards or backwards.
2003
2022
*/
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 );
2006
2024
}
2007
2025
2008
2026
if (do_sync ) {
@@ -2019,10 +2037,15 @@ static void text_poke_bp_batch(struct text_poke_loc *tp, unsigned int nr_entries
2019
2037
* replacing opcode.
2020
2038
*/
2021
2039
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 )
2023
2046
continue ;
2024
2047
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 );
2026
2049
do_sync ++ ;
2027
2050
}
2028
2051
@@ -2040,9 +2063,11 @@ static void text_poke_loc_init(struct text_poke_loc *tp, void *addr,
2040
2063
const void * opcode , size_t len , const void * emulate )
2041
2064
{
2042
2065
struct insn insn ;
2043
- int ret , i ;
2066
+ int ret , i = 0 ;
2044
2067
2045
- memcpy ((void * )tp -> text , opcode , len );
2068
+ if (len == 6 )
2069
+ i = 1 ;
2070
+ memcpy ((void * )tp -> text , opcode + i , len - i );
2046
2071
if (!emulate )
2047
2072
emulate = opcode ;
2048
2073
@@ -2053,6 +2078,13 @@ static void text_poke_loc_init(struct text_poke_loc *tp, void *addr,
2053
2078
tp -> len = len ;
2054
2079
tp -> opcode = insn .opcode .bytes [0 ];
2055
2080
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
+
2056
2088
switch (tp -> opcode ) {
2057
2089
case RET_INSN_OPCODE :
2058
2090
case JMP32_INSN_OPCODE :
@@ -2069,7 +2101,6 @@ static void text_poke_loc_init(struct text_poke_loc *tp, void *addr,
2069
2101
BUG_ON (len != insn .length );
2070
2102
}
2071
2103
2072
-
2073
2104
switch (tp -> opcode ) {
2074
2105
case INT3_INSN_OPCODE :
2075
2106
case RET_INSN_OPCODE :
@@ -2078,6 +2109,7 @@ static void text_poke_loc_init(struct text_poke_loc *tp, void *addr,
2078
2109
case CALL_INSN_OPCODE :
2079
2110
case JMP32_INSN_OPCODE :
2080
2111
case JMP8_INSN_OPCODE :
2112
+ case 0x70 ... 0x7f : /* Jcc */
2081
2113
tp -> disp = insn .immediate .value ;
2082
2114
break ;
2083
2115
0 commit comments