Home | History | Annotate | Line # | Download | only in gdb.btrace
      1 # This testcase is part of GDB, the GNU debugger.
      2 #
      3 # Copyright 2024 Free Software Foundation, Inc.
      4 #
      5 # This program is free software; you can redistribute it and/or modify
      6 # it under the terms of the GNU General Public License as published by
      7 # the Free Software Foundation; either version 3 of the License, or
      8 # (at your option) any later version.
      9 #
     10 # This program is distributed in the hope that it will be useful,
     11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 # GNU General Public License for more details.
     14 #
     15 # You should have received a copy of the GNU General Public License
     16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 
     18 load_lib gdb-python.exp
     19 
     20 require allow_btrace_ptw_tests allow_python_tests
     21 
     22 set opts {}
     23 
     24 if [info exists COMPILE] {
     25     # make check RUNTESTFLAGS="gdb.btrace/ptwrite.exp COMPILE=1"
     26     standard_testfile ptwrite.c
     27     lappend opts debug additional_flags=-mptwrite
     28 } elseif {[istarget "i?86-*-*"] || [istarget "x86_64-*-*"]} {
     29     if {[is_amd64_regs_target]} {
     30 	standard_testfile x86_64-ptwrite.S
     31     } else {
     32 	standard_testfile i386-ptwrite.S
     33     }
     34 } else {
     35     unsupported "target architecture not supported"
     36     return -1
     37 }
     38 
     39 if [prepare_for_testing "failed to prepare" $testfile $srcfile $opts] {
     40     return -1
     41 }
     42 
     43 if { ![runto_main] } {
     44     untested "failed to run to main"
     45     return -1
     46 }
     47 
     48 ### 1. Default testrun
     49 
     50 # Setup recording
     51 gdb_test_no_output "set record instruction-history-size unlimited"
     52 gdb_test_no_output "record btrace pt"
     53 gdb_test "next 2" ".*"
     54 
     55 with_test_prefix "Default" {
     56     # Test record instruction-history
     57     gdb_test "record instruction-history 1" [multi_line \
     58 	".*\[0-9\]+\t   $hex <ptwrite1\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
     59 	"\[0-9\]+\t     \\\[0x42\\\]" \
     60 	".*\[0-9\]+\t   $hex <ptwrite2\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
     61 	"\[0-9\]+\t     \\\[0x43\\\].*" \
     62 	]
     63 
     64     gdb_test "record instruction-history /a 1" [multi_line \
     65 	".*\[0-9\]+\t   $hex <ptwrite1\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
     66 	".*\[0-9\]+\t   $hex <ptwrite2\\+\[0-9\]+>:\tptwrite %\[a-z\]+.*" \
     67 	]
     68 
     69     # Test function call history
     70     gdb_test "record function-call-history 1,4" [multi_line \
     71 	"1\tmain" \
     72 	"2\tptwrite1" \
     73 	"\t  \\\[0x42\\\]" \
     74 	"3\tmain" \
     75 	"4\tptwrite2" \
     76 	"\t  \\\[0x43\\\]" \
     77 	]
     78 
     79     gdb_test "record function-call-history /a 1,4" [multi_line \
     80 	"1\tmain" \
     81 	"2\tptwrite1" \
     82 	"3\tmain" \
     83 	"4\tptwrite2" \
     84 	]
     85 }
     86 
     87 # Test payload printing during stepping
     88 with_test_prefix "Stepping" {
     89     gdb_test "record goto 10" "Can't go to an auxiliary instruction\."
     90     gdb_test "record goto 9" ".*ptwrite.* at .*"
     91     gdb_test "stepi" ".*\\\[0x42\\\].*"
     92     gdb_test "reverse-stepi" ".*\\\[0x42\\\].*"
     93     gdb_test "continue" [multi_line \
     94 	    ".*\\\[0x42\\\]" \
     95 	    "\\\[0x43\\\].*" \
     96 	    ]
     97     gdb_test "reverse-continue" [multi_line \
     98 	    ".*\\\[0x43\\\]" \
     99 	    "\\\[0x42\\\].*" \
    100 	    ]
    101 }
    102 
    103 # Test auxiliary type in python
    104 gdb_test_multiline "auxiliary type in python" \
    105     "python" "" \
    106     "h = gdb.current_recording().instruction_history" "" \
    107     "for insn in h:" "" \
    108     "    if hasattr(insn, 'decoded'):" "" \
    109     "        print(insn.decoded.decode())" "" \
    110     "    elif hasattr(insn, 'data'):" "" \
    111     "        print(insn.data)" "" \
    112     "end" \
    113     [multi_line \
    114 	".*mov    -0x4\\\(%(e|r)bp\\\),%(e|r)ax" \
    115 	"ptwrite %eax" \
    116 	"0x42" \
    117 	"nop.*" \
    118 	"mov    -0x4\\\(%(e|r)bp\\\),%(e|r)ax" \
    119 	"ptwrite %eax" \
    120 	"0x43" \
    121 	"nop.*"
    122     ]
    123 
    124 
    125 ### 2. Test filter registration
    126 ### 2.1 Custom filter
    127 with_test_prefix "Custom" {
    128     gdb_test_multiline "register filter in python" \
    129 	"python" "" \
    130 	"def my_filter(payload, ip):" "" \
    131 	"    if  payload == 66:" "" \
    132 	"        return \"payload: {0}, ip: {1:#x}\".format(payload, ip)" "" \
    133 	"    else:" "" \
    134 	"        return None" "" \
    135 	"def factory(thread): return my_filter" "" \
    136 	"import gdb.ptwrite" "" \
    137 	"gdb.ptwrite.register_filter_factory(factory)" "" \
    138 	"end" ""
    139 
    140     gdb_test "record instruction-history 1" [multi_line \
    141 	".*\[0-9\]+\t   $hex <ptwrite1\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
    142 	"\[0-9\]+\t     \\\[payload: 66, ip: $hex\\\]" \
    143 	".*\[0-9\]+\t   $hex <ptwrite2\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
    144 	"\[0-9\]+\t   $hex <ptwrite2\\+\[0-9\]+>:.*" \
    145 	]
    146 }
    147 
    148 ### 2.2 None as filter. This resets the default behavior.
    149 with_test_prefix "None" {
    150     gdb_test_multiline "register filter in python" \
    151 	"python" "" \
    152 	"import gdb.ptwrite" "" \
    153 	"gdb.ptwrite.register_filter_factory(None)" "" \
    154 	"end" ""
    155 
    156     gdb_test "record instruction-history 1" [multi_line \
    157 	".*\[0-9\]+\t   $hex <ptwrite1\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
    158 	"\[0-9\]+\t     \\\[0x42\\\]" \
    159 	".*\[0-9\]+\t   $hex <ptwrite2\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
    160 	"\[0-9\]+\t     \\\[0x43\\\].*" \
    161 	]
    162 }
    163 
    164 ### 2.3 Lambdas as filter
    165 with_test_prefix "Lambdas" {
    166     gdb_test_multiline "register filter in python" \
    167 	"python" "" \
    168 	"import gdb.ptwrite" "" \
    169 	"lambda_filter = lambda payload, ip: \"{}\".format(payload + 2)" "" \
    170 	"gdb.ptwrite.register_filter_factory(lambda thread : lambda_filter)" "" \
    171 	"end" ""
    172 
    173     gdb_test "record instruction-history 1" [multi_line \
    174 	".*\[0-9\]+\t   $hex <ptwrite1\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
    175 	"\[0-9\]+\t     \\\[68\\\]" \
    176 	".*\[0-9\]+\t   $hex <ptwrite2\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
    177 	"\[0-9\]+\t     \\\[69\\\].*" \
    178 	] "Lambdas: record instruction-history 1"
    179 }
    180 
    181 ### 2.4 Functors as filter
    182 with_test_prefix "Functors" {
    183     gdb_test_multiline "register filter in python" \
    184 	"python" "" \
    185 	"import gdb.ptwrite" "" \
    186 	"class foobar(object):" "" \
    187 	"    def __init__(self):" "" \
    188 	"        self.variable = 0" "" \
    189 	"    def __call__(self, payload, ip):" "" \
    190 	"        self.variable += 1" "" \
    191 	"        return \"{}, {}\".format(self.variable, payload)" "" \
    192 	"gdb.ptwrite.register_filter_factory(lambda thread : foobar())" "" \
    193 	"end" ""
    194 
    195     gdb_test "record instruction-history 1" [multi_line \
    196 	".*\[0-9\]+\t   $hex <ptwrite1\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
    197 	"\[0-9\]+\t     \\\[1, 66\\\]" \
    198 	".*\[0-9\]+\t   $hex <ptwrite2\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
    199 	"\[0-9\]+\t     \\\[2, 67\\\].*" \
    200 	] "Functors: record instruction-history 1"
    201 }
    202