sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1 | |
| 2 | /*--------------------------------------------------------------------*/ |
| 3 | /*--- Handle remote gdb protocol. m_gdbserver.c ---*/ |
| 4 | /*--------------------------------------------------------------------*/ |
| 5 | |
| 6 | /* |
| 7 | This file is part of Valgrind, a dynamic binary instrumentation |
| 8 | framework. |
| 9 | |
Elliott Hughes | ed39800 | 2017-06-21 14:41:24 -0700 | [diff] [blame^] | 10 | Copyright (C) 2011-2017 Philippe Waroquiers |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 11 | |
| 12 | This program is free software; you can redistribute it and/or |
| 13 | modify it under the terms of the GNU General Public License as |
| 14 | published by the Free Software Foundation; either version 2 of the |
| 15 | License, or (at your option) any later version. |
| 16 | |
| 17 | This program is distributed in the hope that it will be useful, but |
| 18 | WITHOUT ANY WARRANTY; without even the implied warranty of |
| 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 20 | General Public License for more details. |
| 21 | |
| 22 | You should have received a copy of the GNU General Public License |
| 23 | along with this program; if not, write to the Free Software |
| 24 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 25 | 02111-1307, USA. |
| 26 | |
| 27 | The GNU General Public License is contained in the file COPYING. |
| 28 | */ |
| 29 | |
| 30 | #include "pub_core_basics.h" |
| 31 | #include "pub_core_vki.h" |
| 32 | #include "pub_core_debuglog.h" |
| 33 | #include "pub_core_libcproc.h" |
| 34 | #include "pub_core_libcprint.h" |
| 35 | #include "pub_core_mallocfree.h" |
philippe | 0447bbd | 2012-10-17 21:32:03 +0000 | [diff] [blame] | 36 | #include "pub_core_threadstate.h" |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 37 | #include "pub_core_gdbserver.h" |
| 38 | #include "pub_core_options.h" |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 39 | #include "pub_core_transtab.h" |
florian | c91f584 | 2013-09-15 10:42:26 +0000 | [diff] [blame] | 40 | #include "pub_core_hashtable.h" |
| 41 | #include "pub_core_xarray.h" |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 42 | #include "pub_core_libcassert.h" |
florian | c91f584 | 2013-09-15 10:42:26 +0000 | [diff] [blame] | 43 | #include "pub_core_libcbase.h" |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 44 | #include "pub_core_libcsignal.h" |
philippe | 886fde3 | 2012-03-29 21:56:47 +0000 | [diff] [blame] | 45 | #include "pub_core_signals.h" |
florian | c91f584 | 2013-09-15 10:42:26 +0000 | [diff] [blame] | 46 | #include "pub_core_machine.h" // VG_(fnptr_to_fnentry) |
| 47 | #include "pub_core_debuginfo.h" |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 48 | #include "pub_core_scheduler.h" |
| 49 | #include "pub_core_syswrap.h" |
| 50 | |
| 51 | #include "server.h" |
| 52 | |
| 53 | Int VG_(dyn_vgdb_error); |
| 54 | |
| 55 | /* forward declarations */ |
| 56 | VG_REGPARM(1) |
| 57 | void VG_(helperc_CallDebugger) ( HWord iaddr ); |
| 58 | VG_REGPARM(1) |
| 59 | void VG_(helperc_invalidate_if_not_gdbserved) ( Addr addr ); |
florian | 1636d33 | 2012-11-15 04:27:04 +0000 | [diff] [blame] | 60 | static void invalidate_current_ip (ThreadId tid, const HChar *who); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 61 | |
| 62 | /* reasons of call to call_gdbserver. */ |
| 63 | typedef |
| 64 | enum { |
| 65 | init_reason, // initialises gdbserver resources |
| 66 | vgdb_reason, // gdbserver invocation by vgdb doing ptrace |
| 67 | core_reason, // gdbserver invocation by core (e.g. error encountered) |
| 68 | break_reason, // break encountered |
| 69 | watch_reason, // watchpoint detected by tool |
philippe | 0447bbd | 2012-10-17 21:32:03 +0000 | [diff] [blame] | 70 | signal_reason, // signal encountered |
| 71 | exit_reason} // process terminated |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 72 | CallReason; |
| 73 | |
florian | 1636d33 | 2012-11-15 04:27:04 +0000 | [diff] [blame] | 74 | static const HChar* ppCallReason(CallReason reason) |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 75 | { |
| 76 | switch (reason) { |
| 77 | case init_reason: return "init_reason"; |
| 78 | case vgdb_reason: return "vgdb_reason"; |
| 79 | case core_reason: return "core_reason"; |
| 80 | case break_reason: return "break_reason"; |
| 81 | case watch_reason: return "watch_reason"; |
| 82 | case signal_reason: return "signal_reason"; |
philippe | 0447bbd | 2012-10-17 21:32:03 +0000 | [diff] [blame] | 83 | case exit_reason: return "exit_reason"; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 84 | default: vg_assert (0); |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | /* An instruction instrumented for gdbserver looks like this: |
| 89 | 1. Ist_Mark (0x1234) |
sewardj | 6b7357b | 2011-05-27 13:23:44 +0000 | [diff] [blame] | 90 | 2. Put (IP, 0x1234) |
| 91 | 3. helperc_CallDebugger (0x1234) |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 92 | This will give control to gdb if there is a break at 0x1234 |
| 93 | or if we are single stepping |
sewardj | 6b7357b | 2011-05-27 13:23:44 +0000 | [diff] [blame] | 94 | 4. ... here the real IR for the instruction at 0x1234 |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 95 | |
| 96 | When there is a break at 0x1234: |
| 97 | if user does "continue" or "step" or similar, |
| 98 | then - the call to debugger returns |
| 99 | - valgrind executes at 3. the real IR(s) for 0x1234 |
| 100 | |
| 101 | if as part of helperc_CallDebugger, the user calls |
| 102 | some code in gdb e.g print hello_world() |
| 103 | then - gdb prepares a dummy stack frame with a specific |
| 104 | return address (typically it uses _start) and |
| 105 | inserts a break at this address |
| 106 | - gdb then puts in EIP the address of hello_world() |
| 107 | - gdb then continues (so the helperc_CallDebugger |
| 108 | returns) |
| 109 | - call_gdbserver() function will then return the |
| 110 | control to the scheduler (using VG_MINIMAL_LONGJMP) |
| 111 | to allow the block of the new EIP |
| 112 | to be executed. |
| 113 | - hello_world code is executed. |
| 114 | - when hello_world() returns, it returns to |
| 115 | _start and encounters the break at _start. |
| 116 | - gdb then removes this break, put 0x1234 in EIP |
| 117 | and does a "step". This causes to jump from |
| 118 | _start to 0x1234, where the call to |
| 119 | helperc_CallDebugger is redone. |
| 120 | - This is all ok, the user can then give new gdb |
| 121 | commands. |
| 122 | |
| 123 | However, when continue is given, address 0x1234 is to |
| 124 | be executed: gdb gives a single step, which must not |
| 125 | report again the break at 0x1234. To avoid a 2nd report |
| 126 | of the same break, the below tells that the next |
| 127 | helperc_CallDebugger call must ignore a break/stop at |
| 128 | this address. |
| 129 | */ |
| 130 | static Addr ignore_this_break_once = 0; |
| 131 | |
| 132 | |
| 133 | static void call_gdbserver ( ThreadId tid , CallReason reason); |
| 134 | |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 135 | /* Describes the address addr (for debugging/printing purposes). |
| 136 | Last two results are kept. A third call will replace the |
| 137 | oldest result. */ |
florian | 1636d33 | 2012-11-15 04:27:04 +0000 | [diff] [blame] | 138 | static HChar* sym (Addr addr, Bool is_code) |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 139 | { |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 140 | static HChar *buf[2]; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 141 | static int w = 0; |
| 142 | PtrdiffT offset; |
| 143 | if (w == 2) w = 0; |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 144 | |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 145 | if (is_code) { |
florian | 770a8d2 | 2014-11-03 22:43:42 +0000 | [diff] [blame] | 146 | const HChar *name; |
| 147 | name = VG_(describe_IP) (addr, NULL); |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 148 | if (buf[w]) VG_(free)(buf[w]); |
| 149 | buf[w] = VG_(strdup)("gdbserver sym", name); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 150 | } else { |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 151 | const HChar *name; |
| 152 | VG_(get_datasym_and_offset) (addr, &name, &offset); |
| 153 | if (buf[w]) VG_(free)(buf[w]); |
| 154 | buf[w] = VG_(strdup)("gdbserver sym", name); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 155 | } |
| 156 | return buf[w++]; |
| 157 | } |
| 158 | |
| 159 | /* Each time gdbserver is called, gdbserver_called is incremented |
| 160 | gdbserver_exited is incremented when gdbserver is asked to exit */ |
| 161 | static int gdbserver_called = 0; |
| 162 | static int gdbserver_exited = 0; |
| 163 | |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 164 | /* alloc and free functions for xarray and similar. */ |
florian | 54fe202 | 2012-10-27 23:07:42 +0000 | [diff] [blame] | 165 | static void* gs_alloc (const HChar* cc, SizeT sz) |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 166 | { |
florian | 77eb20b | 2014-09-11 21:19:17 +0000 | [diff] [blame] | 167 | return VG_(malloc)(cc, sz); |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 168 | } |
| 169 | static void gs_free (void* ptr) |
| 170 | { |
florian | 77eb20b | 2014-09-11 21:19:17 +0000 | [diff] [blame] | 171 | VG_(free)(ptr); |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 172 | } |
| 173 | |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 174 | typedef |
| 175 | enum { |
| 176 | GS_break, |
| 177 | GS_jump |
| 178 | } |
| 179 | GS_Kind; |
| 180 | |
| 181 | typedef |
| 182 | struct _GS_Address { |
| 183 | struct _GS_Address* next; |
| 184 | Addr addr; |
| 185 | GS_Kind kind; |
| 186 | } |
| 187 | GS_Address; |
| 188 | |
| 189 | /* gs_addresses contains a list of all addresses that have been invalidated |
| 190 | because they have been (or must be) instrumented for gdbserver. |
| 191 | An entry is added in this table when there is a break at this |
| 192 | address (kind == GS_break) or if this address is the jump target of an |
| 193 | exit of a block that has been instrumented for gdbserver while |
| 194 | single stepping (kind == GS_jump). |
| 195 | When gdbserver is not single stepping anymore, all GS_jump entries |
| 196 | are removed, their translations are invalidated. |
sewardj | 6b7357b | 2011-05-27 13:23:44 +0000 | [diff] [blame] | 197 | |
| 198 | Note for ARM: addr in GS_Address is the value without the thumb bit set. |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 199 | */ |
florian | 09a4c79 | 2014-10-18 10:58:05 +0000 | [diff] [blame] | 200 | static VgHashTable *gs_addresses = NULL; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 201 | |
sewardj | 6b7357b | 2011-05-27 13:23:44 +0000 | [diff] [blame] | 202 | // Transform addr in the form stored in the list of addresses. |
| 203 | // For the ARM architecture, we store it with the thumb bit set to 0. |
| 204 | static Addr HT_addr ( Addr addr ) |
| 205 | { |
| 206 | #if defined(VGA_arm) |
| 207 | return addr & ~(Addr)1; |
| 208 | #else |
| 209 | return addr; |
| 210 | #endif |
| 211 | } |
| 212 | |
florian | 1636d33 | 2012-11-15 04:27:04 +0000 | [diff] [blame] | 213 | static void add_gs_address (Addr addr, GS_Kind kind, const HChar* from) |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 214 | { |
| 215 | GS_Address *p; |
| 216 | |
florian | 77eb20b | 2014-09-11 21:19:17 +0000 | [diff] [blame] | 217 | p = VG_(malloc)(from, sizeof(GS_Address)); |
sewardj | 6b7357b | 2011-05-27 13:23:44 +0000 | [diff] [blame] | 218 | p->addr = HT_addr (addr); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 219 | p->kind = kind; |
| 220 | VG_(HT_add_node)(gs_addresses, p); |
sewardj | 6b7357b | 2011-05-27 13:23:44 +0000 | [diff] [blame] | 221 | /* It should be sufficient to discard a range of 1. |
| 222 | We use 2 to ensure the below is not sensitive to the presence |
philippe | 5566301 | 2014-02-12 20:41:58 +0000 | [diff] [blame] | 223 | of thumb bit in the range of addresses to discard. |
| 224 | No need to discard translations for Vg_VgdbFull as all |
| 225 | instructions are in any case vgdb-instrumented. */ |
| 226 | if (VG_(clo_vgdb) != Vg_VgdbFull) |
| 227 | VG_(discard_translations) (addr, 2, from); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 228 | } |
| 229 | |
florian | 1636d33 | 2012-11-15 04:27:04 +0000 | [diff] [blame] | 230 | static void remove_gs_address (GS_Address* g, const HChar* from) |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 231 | { |
| 232 | VG_(HT_remove) (gs_addresses, g->addr); |
philippe | 5566301 | 2014-02-12 20:41:58 +0000 | [diff] [blame] | 233 | // See add_gs_address for the explanation for condition and the range 2 below. |
| 234 | if (VG_(clo_vgdb) != Vg_VgdbFull) |
| 235 | VG_(discard_translations) (g->addr, 2, from); |
florian | 77eb20b | 2014-09-11 21:19:17 +0000 | [diff] [blame] | 236 | VG_(free) (g); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 237 | } |
| 238 | |
florian | 1636d33 | 2012-11-15 04:27:04 +0000 | [diff] [blame] | 239 | const HChar* VG_(ppPointKind) (PointKind kind) |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 240 | { |
| 241 | switch(kind) { |
| 242 | case software_breakpoint: return "software_breakpoint"; |
| 243 | case hardware_breakpoint: return "hardware_breakpoint"; |
| 244 | case write_watchpoint: return "write_watchpoint"; |
| 245 | case read_watchpoint: return "read_watchpoint"; |
| 246 | case access_watchpoint: return "access_watchpoint"; |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 247 | default: return "???wrong PointKind"; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 248 | } |
| 249 | } |
| 250 | |
| 251 | typedef |
| 252 | struct _GS_Watch { |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 253 | Addr addr; |
| 254 | SizeT len; |
| 255 | PointKind kind; |
| 256 | } |
| 257 | GS_Watch; |
| 258 | |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 259 | /* gs_watches contains a list of all addresses+len+kind that are being |
| 260 | watched. */ |
| 261 | static XArray* gs_watches = NULL; |
| 262 | |
| 263 | static inline GS_Watch* index_gs_watches(Word i) |
| 264 | { |
| 265 | return *(GS_Watch **) VG_(indexXA) (gs_watches, i); |
| 266 | } |
| 267 | |
| 268 | /* Returns the GS_Watch matching addr/len/kind and sets *g_ix to its |
| 269 | position in gs_watches. |
| 270 | If no matching GS_Watch is found, returns NULL and sets g_ix to -1. */ |
| 271 | static GS_Watch* lookup_gs_watch (Addr addr, SizeT len, PointKind kind, |
| 272 | Word* g_ix) |
| 273 | { |
| 274 | const Word n_elems = VG_(sizeXA) (gs_watches); |
| 275 | Word i; |
| 276 | GS_Watch *g; |
| 277 | |
| 278 | /* Linear search. If we have many watches, this might be optimised |
| 279 | by having the array sorted and using VG_(lookupXA) */ |
| 280 | for (i = 0; i < n_elems; i++) { |
| 281 | g = index_gs_watches(i); |
| 282 | if (g->addr == addr && g->len == len && g->kind == kind) { |
| 283 | // Found. |
| 284 | *g_ix = i; |
| 285 | return g; |
| 286 | } |
| 287 | } |
| 288 | |
| 289 | // Not found. |
| 290 | *g_ix = -1; |
| 291 | return NULL; |
| 292 | } |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 293 | |
| 294 | |
| 295 | /* protocol spec tells the below must be idempotent. */ |
| 296 | static void breakpoint (Bool insert, CORE_ADDR addr) |
| 297 | { |
| 298 | GS_Address *g; |
| 299 | |
sewardj | 6b7357b | 2011-05-27 13:23:44 +0000 | [diff] [blame] | 300 | g = VG_(HT_lookup) (gs_addresses, (UWord)HT_addr(addr)); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 301 | if (insert) { |
| 302 | /* insert a breakpoint at addr or upgrade its kind */ |
| 303 | if (g == NULL) { |
| 304 | add_gs_address (addr, GS_break, "m_gdbserver breakpoint insert"); |
| 305 | } else { |
| 306 | /* already gdbserved. Normally, it must be because of a jump. |
| 307 | However, due to idempotent or if connection with gdb was |
| 308 | lost (kept breaks from the previous gdb), if already existing, |
| 309 | we just upgrade its kind. */ |
| 310 | g->kind = GS_break; |
| 311 | } |
| 312 | } else { |
| 313 | /* delete a breakpoint at addr or downgrade its kind */ |
| 314 | if (g != NULL && g->kind == GS_break) { |
| 315 | if (valgrind_single_stepping()) { |
| 316 | /* keep gdbserved instrumentation while single stepping */ |
| 317 | g->kind = GS_jump; |
| 318 | } else { |
| 319 | remove_gs_address (g, "m_gdbserver breakpoint remove"); |
| 320 | } |
| 321 | } else { |
| 322 | dlog (1, "remove break addr %p %s\n", |
| 323 | C2v(addr), (g == NULL ? |
| 324 | "NULL" : |
| 325 | (g->kind == GS_jump ? "GS_jump" : "GS_break"))); |
| 326 | } |
| 327 | } |
| 328 | } |
| 329 | |
| 330 | static Bool (*tool_watchpoint) (PointKind kind, |
| 331 | Bool insert, |
| 332 | Addr addr, |
| 333 | SizeT len) = NULL; |
| 334 | void VG_(needs_watchpoint) (Bool (*watchpoint) (PointKind kind, |
| 335 | Bool insert, |
| 336 | Addr addr, |
| 337 | SizeT len)) |
| 338 | { |
| 339 | tool_watchpoint = watchpoint; |
| 340 | } |
| 341 | |
| 342 | Bool VG_(gdbserver_point) (PointKind kind, Bool insert, |
| 343 | CORE_ADDR addr, int len) |
| 344 | { |
| 345 | Bool res; |
| 346 | GS_Watch *g; |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 347 | Word g_ix; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 348 | Bool is_code = kind == software_breakpoint || kind == hardware_breakpoint; |
| 349 | |
| 350 | dlog(1, "%s %s at addr %p %s\n", |
| 351 | (insert ? "insert" : "remove"), |
| 352 | VG_(ppPointKind) (kind), |
| 353 | C2v(addr), |
| 354 | sym(addr, is_code)); |
| 355 | |
| 356 | if (is_code) { |
| 357 | breakpoint (insert, addr); |
| 358 | return True; |
| 359 | } |
| 360 | |
| 361 | vg_assert (kind == access_watchpoint |
| 362 | || kind == read_watchpoint |
| 363 | || kind == write_watchpoint); |
| 364 | |
| 365 | if (tool_watchpoint == NULL) |
| 366 | return False; |
| 367 | |
| 368 | res = (*tool_watchpoint) (kind, insert, addr, len); |
| 369 | if (!res) |
| 370 | return False; /* error or unsupported */ |
| 371 | |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 372 | // Protocol says insert/remove must be idempotent. |
| 373 | // So, we just ignore double insert or (supposed) double delete. |
| 374 | |
| 375 | g = lookup_gs_watch (addr, len, kind, &g_ix); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 376 | if (insert) { |
| 377 | if (g == NULL) { |
florian | 77eb20b | 2014-09-11 21:19:17 +0000 | [diff] [blame] | 378 | g = VG_(malloc)("gdbserver_point watchpoint", sizeof(GS_Watch)); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 379 | g->addr = addr; |
| 380 | g->len = len; |
| 381 | g->kind = kind; |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 382 | VG_(addToXA)(gs_watches, &g); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 383 | } else { |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 384 | dlog(1, |
| 385 | "VG_(gdbserver_point) addr %p len %d kind %s already inserted\n", |
| 386 | C2v(addr), len, VG_(ppPointKind) (kind)); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 387 | } |
| 388 | } else { |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 389 | if (g != NULL) { |
| 390 | VG_(removeIndexXA) (gs_watches, g_ix); |
florian | 77eb20b | 2014-09-11 21:19:17 +0000 | [diff] [blame] | 391 | VG_(free) (g); |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 392 | } else { |
| 393 | dlog(1, |
| 394 | "VG_(gdbserver_point) addr %p len %d kind %s already deleted?\n", |
| 395 | C2v(addr), len, VG_(ppPointKind) (kind)); |
| 396 | } |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 397 | } |
| 398 | return True; |
| 399 | } |
| 400 | |
philippe | 0232098 | 2013-05-02 22:06:31 +0000 | [diff] [blame] | 401 | Bool VG_(has_gdbserver_breakpoint) (Addr addr) |
| 402 | { |
| 403 | GS_Address *g; |
| 404 | if (!gdbserver_called) |
| 405 | return False; |
| 406 | g = VG_(HT_lookup) (gs_addresses, (UWord)HT_addr(addr)); |
| 407 | return (g != NULL && g->kind == GS_break); |
| 408 | } |
| 409 | |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 410 | Bool VG_(is_watched)(PointKind kind, Addr addr, Int szB) |
| 411 | { |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 412 | Word n_elems; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 413 | GS_Watch* g; |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 414 | Word i; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 415 | Bool watched = False; |
| 416 | const ThreadId tid = VG_(running_tid); |
| 417 | |
| 418 | if (!gdbserver_called) |
| 419 | return False; |
| 420 | |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 421 | n_elems = VG_(sizeXA) (gs_watches); |
| 422 | |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 423 | Addr to = addr + szB; // semi-open interval [addr, to[ |
| 424 | |
| 425 | vg_assert (kind == access_watchpoint |
| 426 | || kind == read_watchpoint |
| 427 | || kind == write_watchpoint); |
florian | 654ea86 | 2015-08-06 12:11:33 +0000 | [diff] [blame] | 428 | dlog(1, "tid %u VG_(is_watched) %s addr %p szB %d\n", |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 429 | tid, VG_(ppPointKind) (kind), C2v(addr), szB); |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 430 | |
| 431 | for (i = 0; i < n_elems; i++) { |
| 432 | g = index_gs_watches(i); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 433 | switch (g->kind) { |
| 434 | case software_breakpoint: |
| 435 | case hardware_breakpoint: |
| 436 | break; |
| 437 | case access_watchpoint: |
| 438 | case read_watchpoint: |
| 439 | case write_watchpoint: |
| 440 | if (to <= g->addr || addr >= (g->addr + g->len)) |
| 441 | /* If no overlap, examine next watchpoint: */ |
| 442 | continue; |
| 443 | |
| 444 | watched = True; /* We have an overlap */ |
| 445 | |
| 446 | /* call gdbserver if access kind reported by the tool |
| 447 | matches the watchpoint kind. */ |
| 448 | if (kind == access_watchpoint |
| 449 | || g->kind == access_watchpoint |
| 450 | || g->kind == kind) { |
| 451 | /* Watchpoint encountered. |
| 452 | If this is a read watchpoint, we directly call gdbserver |
| 453 | to report it to gdb. |
| 454 | Otherwise, for a write watchpoint, we have to finish |
| 455 | the instruction so as to modify the value. |
| 456 | If we do not finish the instruction, then gdb sees no |
| 457 | value change and continues. |
| 458 | For a read watchpoint, we better call gdbserver directly: |
| 459 | in case the current block is not gdbserved, Valgrind |
| 460 | will execute instructions till the next block. */ |
| 461 | |
| 462 | /* set the watchpoint stop address to the first read or written. */ |
| 463 | if (g->addr <= addr) { |
| 464 | VG_(set_watchpoint_stop_address) (addr); |
| 465 | } else { |
| 466 | VG_(set_watchpoint_stop_address) (g->addr); |
| 467 | } |
| 468 | |
| 469 | if (kind == write_watchpoint) { |
| 470 | /* Let Valgrind stop as early as possible after this instruction |
| 471 | by switching to Single Stepping mode. */ |
| 472 | valgrind_set_single_stepping (True); |
| 473 | invalidate_current_ip (tid, "m_gdbserver write watchpoint"); |
| 474 | } else { |
| 475 | call_gdbserver (tid, watch_reason); |
| 476 | VG_(set_watchpoint_stop_address) ((Addr) 0); |
| 477 | } |
| 478 | return True; // we are watched here. |
| 479 | } |
| 480 | break; |
| 481 | default: |
| 482 | vg_assert (0); |
| 483 | } |
| 484 | } |
| 485 | return watched; |
| 486 | } |
| 487 | |
| 488 | /* Returns the reason for which gdbserver instrumentation is needed */ |
florian | 3c0c947 | 2014-09-24 12:06:55 +0000 | [diff] [blame] | 489 | static VgVgdb VG_(gdbserver_instrumentation_needed) (const VexGuestExtents* vge) |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 490 | { |
| 491 | GS_Address* g; |
| 492 | int e; |
| 493 | |
| 494 | if (!gdbserver_called) |
| 495 | return Vg_VgdbNo; |
| 496 | |
| 497 | if (valgrind_single_stepping()) { |
| 498 | dlog(2, "gdbserver_instrumentation_needed due to single stepping\n"); |
| 499 | return Vg_VgdbYes; |
| 500 | } |
| 501 | |
| 502 | if (VG_(clo_vgdb) == Vg_VgdbYes && VG_(HT_count_nodes) (gs_addresses) == 0) |
| 503 | return Vg_VgdbNo; |
| 504 | |
| 505 | /* We assume we do not have a huge nr of breakpoints. |
| 506 | Otherwise, we need something more efficient e.g. |
| 507 | a sorted list of breakpoints or associate extents to it or ... |
| 508 | */ |
| 509 | VG_(HT_ResetIter) (gs_addresses); |
| 510 | while ((g = VG_(HT_Next) (gs_addresses))) { |
| 511 | for (e = 0; e < vge->n_used; e++) { |
sewardj | 6b7357b | 2011-05-27 13:23:44 +0000 | [diff] [blame] | 512 | if (g->addr >= HT_addr(vge->base[e]) |
| 513 | && g->addr < HT_addr(vge->base[e]) + vge->len[e]) { |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 514 | dlog(2, |
| 515 | "gdbserver_instrumentation_needed %p %s reason %s\n", |
| 516 | C2v(g->addr), sym(g->addr, /* is_code */ True), |
| 517 | (g->kind == GS_jump ? "GS_jump" : "GS_break")); |
| 518 | return Vg_VgdbYes; |
| 519 | } |
| 520 | } |
| 521 | } |
| 522 | |
| 523 | if (VG_(clo_vgdb) == Vg_VgdbFull) { |
| 524 | dlog(4, "gdbserver_instrumentation_needed" |
| 525 | " due to VG_(clo_vgdb) == Vg_VgdbFull\n"); |
| 526 | return Vg_VgdbFull; |
| 527 | } |
| 528 | |
| 529 | |
| 530 | return Vg_VgdbNo; |
| 531 | } |
| 532 | |
| 533 | // Clear gdbserved_addresses in gs_addresses. |
| 534 | // If clear_only_jumps, clears only the addresses that are served |
| 535 | // for jump reasons. |
| 536 | // Otherwise, clear all the addresses. |
| 537 | // Cleared addresses are invalidated so as to have them re-translated. |
| 538 | static void clear_gdbserved_addresses(Bool clear_only_jumps) |
| 539 | { |
| 540 | GS_Address** ag; |
| 541 | UInt n_elems; |
| 542 | int i; |
| 543 | |
| 544 | dlog(1, |
florian | a6a6d92 | 2015-08-05 11:26:10 +0000 | [diff] [blame] | 545 | "clear_gdbserved_addresses: scanning hash table nodes %u\n", |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 546 | VG_(HT_count_nodes) (gs_addresses)); |
| 547 | ag = (GS_Address**) VG_(HT_to_array) (gs_addresses, &n_elems); |
| 548 | for (i = 0; i < n_elems; i++) |
| 549 | if (!clear_only_jumps || ag[i]->kind == GS_jump) |
| 550 | remove_gs_address (ag[i], "clear_gdbserved_addresses"); |
| 551 | VG_(free) (ag); |
| 552 | } |
| 553 | |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 554 | // Clear watched addressed in gs_watches, delete gs_watches. |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 555 | static void clear_watched_addresses(void) |
| 556 | { |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 557 | GS_Watch* g; |
| 558 | const Word n_elems = VG_(sizeXA) (gs_watches); |
| 559 | Word i; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 560 | |
| 561 | dlog(1, |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 562 | "clear_watched_addresses: %ld elements\n", |
| 563 | n_elems); |
| 564 | |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 565 | for (i = 0; i < n_elems; i++) { |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 566 | g = index_gs_watches(i); |
| 567 | if (!VG_(gdbserver_point) (g->kind, |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 568 | /* insert */ False, |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 569 | g->addr, |
| 570 | g->len)) { |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 571 | vg_assert (0); |
| 572 | } |
| 573 | } |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 574 | |
| 575 | VG_(deleteXA) (gs_watches); |
| 576 | gs_watches = NULL; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 577 | } |
| 578 | |
florian | 1636d33 | 2012-11-15 04:27:04 +0000 | [diff] [blame] | 579 | static void invalidate_if_jump_not_yet_gdbserved (Addr addr, const HChar* from) |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 580 | { |
sewardj | 6b7357b | 2011-05-27 13:23:44 +0000 | [diff] [blame] | 581 | if (VG_(HT_lookup) (gs_addresses, (UWord)HT_addr(addr))) |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 582 | return; |
| 583 | add_gs_address (addr, GS_jump, from); |
| 584 | } |
| 585 | |
florian | 1636d33 | 2012-11-15 04:27:04 +0000 | [diff] [blame] | 586 | static void invalidate_current_ip (ThreadId tid, const HChar *who) |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 587 | { |
| 588 | invalidate_if_jump_not_yet_gdbserved (VG_(get_IP) (tid), who); |
| 589 | } |
| 590 | |
philippe | 180a750 | 2014-04-20 13:41:10 +0000 | [diff] [blame] | 591 | Bool VG_(gdbserver_init_done) (void) |
| 592 | { |
| 593 | return gdbserver_called > 0; |
| 594 | } |
| 595 | |
| 596 | Bool VG_(gdbserver_stop_at) (VgdbStopAt stopat) |
| 597 | { |
| 598 | return gdbserver_called > 0 && VgdbStopAtiS(stopat, VG_(clo_vgdb_stop_at)); |
| 599 | } |
| 600 | |
sewardj | 997546c | 2011-05-17 18:14:53 +0000 | [diff] [blame] | 601 | void VG_(gdbserver_prerun_action) (ThreadId tid) |
| 602 | { |
| 603 | // Using VG_(dyn_vgdb_error) allows the user to control if gdbserver |
| 604 | // stops after a fork. |
philippe | 180a750 | 2014-04-20 13:41:10 +0000 | [diff] [blame] | 605 | if (VG_(dyn_vgdb_error) == 0 |
| 606 | || VgdbStopAtiS(VgdbStopAt_Startup, VG_(clo_vgdb_stop_at))) { |
sewardj | 997546c | 2011-05-17 18:14:53 +0000 | [diff] [blame] | 607 | /* The below call allows gdb to attach at startup |
| 608 | before the first guest instruction is executed. */ |
| 609 | VG_(umsg)("(action at startup) vgdb me ... \n"); |
| 610 | VG_(gdbserver)(tid); |
| 611 | } else { |
| 612 | /* User has activated gdbserver => initialize now the FIFOs |
| 613 | to let vgdb/gdb contact us either via the scheduler poll |
| 614 | mechanism or via vgdb ptrace-ing valgrind. */ |
| 615 | if (VG_(gdbserver_activity) (tid)) |
| 616 | VG_(gdbserver) (tid); |
| 617 | } |
| 618 | } |
| 619 | |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 620 | /* when fork is done, various cleanup is needed in the child process. |
| 621 | In particular, child must have its own connection to avoid stealing |
| 622 | data from its parent */ |
| 623 | static void gdbserver_cleanup_in_child_after_fork(ThreadId me) |
| 624 | { |
florian | 654ea86 | 2015-08-06 12:11:33 +0000 | [diff] [blame] | 625 | dlog(1, "thread %u gdbserver_cleanup_in_child_after_fork pid %d\n", |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 626 | me, VG_(getpid) ()); |
| 627 | |
| 628 | /* finish connection inheritated from parent */ |
| 629 | remote_finish(reset_after_fork); |
| 630 | |
| 631 | /* ensure next call to gdbserver will be considered as a brand |
| 632 | new call that will initialize a fresh gdbserver. */ |
| 633 | if (gdbserver_called) { |
| 634 | gdbserver_called = 0; |
| 635 | vg_assert (gs_addresses != NULL); |
| 636 | vg_assert (gs_watches != NULL); |
| 637 | clear_gdbserved_addresses(/* clear only jumps */ False); |
philippe | 6643e96 | 2012-01-17 21:16:30 +0000 | [diff] [blame] | 638 | VG_(HT_destruct) (gs_addresses, VG_(free)); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 639 | gs_addresses = NULL; |
| 640 | clear_watched_addresses(); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 641 | } else { |
| 642 | vg_assert (gs_addresses == NULL); |
| 643 | vg_assert (gs_watches == NULL); |
| 644 | } |
sewardj | 997546c | 2011-05-17 18:14:53 +0000 | [diff] [blame] | 645 | |
| 646 | |
| 647 | if (VG_(clo_trace_children)) { |
| 648 | VG_(gdbserver_prerun_action) (me); |
| 649 | } |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 650 | } |
| 651 | |
| 652 | /* If reason is init_reason, creates the connection resources (e.g. |
| 653 | the FIFOs) to allow a gdb connection to be detected by polling |
| 654 | using remote_desc_activity. |
| 655 | Otherwise (other reasons): |
| 656 | If connection with gdb not yet opened, opens the connection with gdb. |
| 657 | reads gdb remote protocol packets and executes the requested commands. |
| 658 | */ |
| 659 | static void call_gdbserver ( ThreadId tid , CallReason reason) |
| 660 | { |
| 661 | ThreadState* tst = VG_(get_ThreadState)(tid); |
| 662 | int stepping; |
| 663 | Addr saved_pc; |
| 664 | |
| 665 | dlog(1, |
florian | 654ea86 | 2015-08-06 12:11:33 +0000 | [diff] [blame] | 666 | "entering call_gdbserver %s ... pid %d tid %u status %s " |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 667 | "sched_jmpbuf_valid %d\n", |
| 668 | ppCallReason (reason), |
| 669 | VG_(getpid) (), tid, VG_(name_of_ThreadStatus)(tst->status), |
| 670 | tst->sched_jmpbuf_valid); |
| 671 | |
philippe | 0447bbd | 2012-10-17 21:32:03 +0000 | [diff] [blame] | 672 | /* If we are about to die, then just run server_main() once to get |
| 673 | the resume reply out and return immediately because most of the state |
| 674 | of this tid and process is about to be torn down. */ |
| 675 | if (reason == exit_reason) { |
| 676 | server_main(); |
| 677 | return; |
| 678 | } |
| 679 | |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 680 | vg_assert(VG_(is_valid_tid)(tid)); |
| 681 | saved_pc = VG_(get_IP) (tid); |
| 682 | |
| 683 | if (gdbserver_exited) { |
| 684 | dlog(0, "call_gdbserver called when gdbserver_exited %d\n", |
| 685 | gdbserver_exited); |
| 686 | return; |
| 687 | } |
| 688 | |
| 689 | if (gdbserver_called == 0) { |
| 690 | vg_assert (gs_addresses == NULL); |
| 691 | vg_assert (gs_watches == NULL); |
| 692 | gs_addresses = VG_(HT_construct)( "gdbserved_addresses" ); |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 693 | gs_watches = VG_(newXA)(gs_alloc, |
| 694 | "gdbserved_watches", |
| 695 | gs_free, |
| 696 | sizeof(GS_Watch*)); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 697 | VG_(atfork)(NULL, NULL, gdbserver_cleanup_in_child_after_fork); |
| 698 | } |
| 699 | vg_assert (gs_addresses != NULL); |
| 700 | vg_assert (gs_watches != NULL); |
| 701 | |
| 702 | gdbserver_called++; |
| 703 | |
| 704 | /* call gdbserver_init if this is the first call to gdbserver. */ |
| 705 | if (gdbserver_called == 1) |
| 706 | gdbserver_init(); |
| 707 | |
| 708 | if (reason == init_reason || gdbserver_called == 1) |
| 709 | remote_open(VG_(clo_vgdb_prefix)); |
| 710 | |
| 711 | /* if the call reason is to initialize, then return control to |
| 712 | valgrind. After this initialization, gdbserver will be called |
| 713 | again either if there is an error detected by valgrind or |
| 714 | if vgdb sends data to the valgrind process. */ |
| 715 | if (reason == init_reason) { |
| 716 | return; |
| 717 | } |
| 718 | |
| 719 | stepping = valgrind_single_stepping(); |
| 720 | |
| 721 | server_main(); |
| 722 | |
| 723 | ignore_this_break_once = valgrind_get_ignore_break_once(); |
| 724 | if (ignore_this_break_once) |
| 725 | dlog(1, "!!! will ignore_this_break_once %s\n", |
| 726 | sym(ignore_this_break_once, /* is_code */ True)); |
| 727 | |
| 728 | |
| 729 | if (valgrind_single_stepping()) { |
| 730 | /* we are single stepping. If we were not stepping on entry, |
| 731 | then invalidate the current program counter so as to properly |
| 732 | do single step. In case the program counter was changed by |
| 733 | gdb, this will also invalidate the target address we will |
| 734 | jump to. */ |
| 735 | if (!stepping && tid != 0) { |
| 736 | invalidate_current_ip (tid, "m_gdbserver single step"); |
| 737 | } |
| 738 | } else { |
| 739 | /* We are not single stepping. If we were stepping on entry, |
| 740 | then clear the gdbserved addresses. This will cause all |
| 741 | these gdbserved blocks to be invalidated so that they can be |
| 742 | re-translated without being gdbserved. */ |
| 743 | if (stepping) |
| 744 | clear_gdbserved_addresses(/* clear only jumps */ True); |
| 745 | } |
| 746 | |
| 747 | /* can't do sanity check at beginning. At least the stack |
| 748 | check is not yet possible. */ |
| 749 | if (gdbserver_called > 1) |
| 750 | VG_(sanity_check_general) (/* force_expensive */ False); |
| 751 | |
| 752 | /* If the PC has been changed by gdb, then we VG_MINIMAL_LONGJMP to |
| 753 | the scheduler to execute the block of the new PC. |
| 754 | Otherwise we just return to continue executing the |
| 755 | current block. */ |
| 756 | if (VG_(get_IP) (tid) != saved_pc) { |
florian | 654ea86 | 2015-08-06 12:11:33 +0000 | [diff] [blame] | 757 | dlog(1, "tid %u %s PC changed from %s to %s\n", |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 758 | tid, VG_(name_of_ThreadStatus) (tst->status), |
| 759 | sym(saved_pc, /* is_code */ True), |
| 760 | sym(VG_(get_IP) (tid), /* is_code */ True)); |
| 761 | if (tst->status == VgTs_Yielding) { |
| 762 | SysRes sres; |
| 763 | VG_(memset)(&sres, 0, sizeof(SysRes)); |
| 764 | VG_(acquire_BigLock)(tid, "gdbsrv VG_MINIMAL_LONGJMP"); |
| 765 | } |
| 766 | if (tst->sched_jmpbuf_valid) { |
| 767 | /* resume scheduler */ |
| 768 | VG_MINIMAL_LONGJMP(tst->sched_jmpbuf); |
| 769 | } |
| 770 | /* else continue to run */ |
| 771 | } |
| 772 | /* continue to run */ |
| 773 | } |
| 774 | |
| 775 | /* busy > 0 when gdbserver is currently being called. |
florian | ad4e979 | 2015-07-05 21:53:33 +0000 | [diff] [blame] | 776 | busy is used to avoid vgdb invoking gdbserver |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 777 | while gdbserver by Valgrind. */ |
| 778 | static volatile int busy = 0; |
| 779 | |
| 780 | void VG_(gdbserver) ( ThreadId tid ) |
| 781 | { |
| 782 | busy++; |
| 783 | /* called by the rest of valgrind for |
| 784 | --vgdb-error=0 reason |
| 785 | or by scheduler "poll/debug/interrupt" reason |
| 786 | or to terminate. */ |
| 787 | if (tid != 0) { |
| 788 | call_gdbserver (tid, core_reason); |
| 789 | } else { |
| 790 | if (gdbserver_called == 0) { |
| 791 | dlog(1, "VG_(gdbserver) called to terminate, nothing to terminate\n"); |
| 792 | } else if (gdbserver_exited) { |
philippe | 2a40c7e | 2015-08-30 15:44:07 +0000 | [diff] [blame] | 793 | dlog(1, "VG_(gdbserver) called to terminate again %d\n", |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 794 | gdbserver_exited); |
| 795 | } else { |
| 796 | gdbserver_terminate(); |
| 797 | gdbserver_exited++; |
| 798 | } |
| 799 | } |
| 800 | busy--; |
| 801 | } |
| 802 | |
| 803 | // nr of invoke_gdbserver while gdbserver is already executing. |
| 804 | static int interrupts_while_busy = 0; |
| 805 | |
| 806 | // nr of invoke_gdbserver while gdbserver is not executing. |
| 807 | static int interrupts_non_busy = 0; |
| 808 | |
| 809 | // nr of invoke_gdbserver when some threads are not interruptible. |
| 810 | static int interrupts_non_interruptible = 0; |
| 811 | |
| 812 | /* When all threads are blocked in a system call, the Valgrind |
| 813 | scheduler cannot poll the shared memory for gdbserver activity. In |
Elliott Hughes | ed39800 | 2017-06-21 14:41:24 -0700 | [diff] [blame^] | 814 | such a case, vgdb will force the invocation of gdbserver using |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 815 | ptrace. To do that, vgdb 'pushes' a call to invoke_gdbserver |
| 816 | on the stack using ptrace. invoke_gdbserver must not return. |
| 817 | Instead, it must call give_control_back_to_vgdb. |
sewardj | b2572b5 | 2011-06-26 09:36:38 +0000 | [diff] [blame] | 818 | vgdb expects to receive a SIGSTOP, which this function generates. |
| 819 | When vgdb gets this SIGSTOP, it knows invoke_gdbserver call |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 820 | is finished and can reset the Valgrind process in the state prior to |
| 821 | the 'pushed call' (using ptrace again). |
| 822 | This all works well. However, the user must avoid |
| 823 | 'kill-9ing' vgdb during such a pushed call, otherwise |
sewardj | b2572b5 | 2011-06-26 09:36:38 +0000 | [diff] [blame] | 824 | the SIGSTOP generated below will be seen by the Valgrind core, |
| 825 | instead of being handled by vgdb. The OS will then handle the SIGSTOP |
| 826 | by stopping the Valgrind process. |
| 827 | We use SIGSTOP as this process cannot be masked. */ |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 828 | |
| 829 | static void give_control_back_to_vgdb(void) |
| 830 | { |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 831 | #if !defined(VGO_solaris) |
sewardj | b2572b5 | 2011-06-26 09:36:38 +0000 | [diff] [blame] | 832 | /* cause a SIGSTOP to be sent to ourself, so that vgdb takes control. |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 833 | vgdb will then restore the stack so as to resume the activity |
| 834 | before the ptrace (typically do_syscall_WRK). */ |
sewardj | b2572b5 | 2011-06-26 09:36:38 +0000 | [diff] [blame] | 835 | if (VG_(kill)(VG_(getpid)(), VKI_SIGSTOP) != 0) |
| 836 | vg_assert2(0, "SIGSTOP for vgdb could not be generated\n"); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 837 | |
| 838 | /* If we arrive here, it means a call was pushed on the stack |
| 839 | by vgdb, but during this call, vgdb and/or connection |
| 840 | died. Alternatively, it is a bug in the vgdb<=>Valgrind gdbserver |
| 841 | ptrace handling. */ |
| 842 | vg_assert2(0, |
| 843 | "vgdb did not took control. Did you kill vgdb ?\n" |
florian | 654ea86 | 2015-08-06 12:11:33 +0000 | [diff] [blame] | 844 | "busy %d vgdb_interrupted_tid %u\n", |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 845 | busy, vgdb_interrupted_tid); |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 846 | #else /* defined(VGO_solaris) */ |
| 847 | /* On Solaris, this code is run within the context of an agent thread |
| 848 | (see vgdb-invoker-solaris.c and "PCAGENT" control message in |
| 849 | proc(4)). Exit the agent thread now. |
| 850 | */ |
| 851 | SysRes sres = VG_(do_syscall0)(SYS_lwp_exit); |
| 852 | if (sr_isError(sres)) |
| 853 | vg_assert2(0, "The agent thread could not be exited\n"); |
| 854 | #endif /* !defined(VGO_solaris) */ |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 855 | } |
| 856 | |
| 857 | /* Using ptrace calls, vgdb will force an invocation of gdbserver. |
| 858 | VG_(invoke_gdbserver) is the entry point called through the |
| 859 | vgdb ptrace technique. */ |
| 860 | void VG_(invoke_gdbserver) ( int check ) |
| 861 | { |
| 862 | /* ******* Avoid non-reentrant function call from here ..... |
| 863 | till the ".... till here" below. */ |
| 864 | |
| 865 | /* We need to determine the state of the various threads to decide |
| 866 | if we directly invoke gdbserver or if we rather indicate to the |
| 867 | scheduler to invoke the gdbserver. To decide that, it is |
| 868 | critical to avoid any "coregrind" function call as the ptrace |
| 869 | might have stopped the process in the middle of this (possibly) |
| 870 | non-rentrant function. So, it is only when all threads are in |
| 871 | an "interruptible" state that we can safely invoke |
| 872 | gdbserver. Otherwise, we let the valgrind scheduler invoke |
| 873 | gdbserver at the next poll. This poll will be made very soon |
| 874 | thanks to a call to VG_(force_vgdb_poll). */ |
| 875 | int n_tid; |
| 876 | |
| 877 | vg_assert (check == 0x8BADF00D); |
| 878 | |
| 879 | if (busy) { |
| 880 | interrupts_while_busy++; |
| 881 | give_control_back_to_vgdb(); |
| 882 | } |
| 883 | interrupts_non_busy++; |
| 884 | |
| 885 | /* check if all threads are in an "interruptible" state. If yes, |
| 886 | we invoke gdbserver. Otherwise, we tell the scheduler to wake up |
| 887 | asap. */ |
| 888 | for (n_tid = 1; n_tid < VG_N_THREADS; n_tid++) { |
| 889 | switch (VG_(threads)[n_tid].status) { |
| 890 | /* interruptible states. */ |
| 891 | case VgTs_WaitSys: |
| 892 | case VgTs_Yielding: |
| 893 | if (vgdb_interrupted_tid == 0) vgdb_interrupted_tid = n_tid; |
| 894 | break; |
| 895 | |
| 896 | case VgTs_Empty: |
| 897 | case VgTs_Zombie: |
| 898 | break; |
| 899 | |
| 900 | /* non interruptible states. */ |
| 901 | case VgTs_Init: |
| 902 | case VgTs_Runnable: |
| 903 | interrupts_non_interruptible++; |
| 904 | VG_(force_vgdb_poll) (); |
| 905 | give_control_back_to_vgdb(); |
| 906 | |
| 907 | default: vg_assert(0); |
| 908 | } |
| 909 | } |
| 910 | |
| 911 | /* .... till here. |
| 912 | From here onwards, function calls are ok: it is |
| 913 | safe to call valgrind core functions: all threads are blocked in |
| 914 | a system call or are yielding or ... */ |
florian | 654ea86 | 2015-08-06 12:11:33 +0000 | [diff] [blame] | 915 | dlog(1, "invoke_gdbserver running_tid %u vgdb_interrupted_tid %u\n", |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 916 | VG_(running_tid), vgdb_interrupted_tid); |
| 917 | call_gdbserver (vgdb_interrupted_tid, vgdb_reason); |
| 918 | vgdb_interrupted_tid = 0; |
| 919 | dlog(1, |
florian | 654ea86 | 2015-08-06 12:11:33 +0000 | [diff] [blame] | 920 | "exit invoke_gdbserver running_tid %u\n", VG_(running_tid)); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 921 | give_control_back_to_vgdb(); |
| 922 | |
| 923 | vg_assert2(0, "end of invoke_gdbserver reached"); |
| 924 | |
| 925 | } |
| 926 | |
| 927 | Bool VG_(gdbserver_activity) (ThreadId tid) |
| 928 | { |
| 929 | Bool ret; |
| 930 | busy++; |
| 931 | if (!gdbserver_called) |
| 932 | call_gdbserver (tid, init_reason); |
| 933 | switch (remote_desc_activity("VG_(gdbserver_activity)")) { |
| 934 | case 0: ret = False; break; |
| 935 | case 1: ret = True; break; |
philippe | 0eb0d5a | 2014-02-11 23:50:16 +0000 | [diff] [blame] | 936 | case 2: |
| 937 | remote_finish(reset_after_error); |
| 938 | call_gdbserver (tid, init_reason); |
| 939 | ret = False; |
| 940 | break; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 941 | default: vg_assert (0); |
| 942 | } |
| 943 | busy--; |
| 944 | return ret; |
| 945 | } |
| 946 | |
philippe | b301469 | 2015-05-17 13:38:25 +0000 | [diff] [blame] | 947 | static void dlog_signal (const HChar *who, const vki_siginfo_t *info, |
| 948 | ThreadId tid) |
philippe | 2d1f256 | 2014-09-19 08:57:29 +0000 | [diff] [blame] | 949 | { |
philippe | b301469 | 2015-05-17 13:38:25 +0000 | [diff] [blame] | 950 | dlog(1, "VG core calling %s " |
florian | 654ea86 | 2015-08-06 12:11:33 +0000 | [diff] [blame] | 951 | "vki_nr %d %s gdb_nr %u %s tid %u\n", |
philippe | b301469 | 2015-05-17 13:38:25 +0000 | [diff] [blame] | 952 | who, |
| 953 | info->si_signo, VG_(signame)(info->si_signo), |
| 954 | target_signal_from_host (info->si_signo), |
| 955 | target_signal_to_name(target_signal_from_host (info->si_signo)), |
philippe | 2d1f256 | 2014-09-19 08:57:29 +0000 | [diff] [blame] | 956 | tid); |
| 957 | |
philippe | b301469 | 2015-05-17 13:38:25 +0000 | [diff] [blame] | 958 | } |
| 959 | |
| 960 | void VG_(gdbserver_report_fatal_signal) (const vki_siginfo_t *info, |
| 961 | ThreadId tid) |
| 962 | { |
| 963 | dlog_signal("VG_(gdbserver_report_fatal_signal)", info, tid); |
| 964 | |
philippe | 2d1f256 | 2014-09-19 08:57:29 +0000 | [diff] [blame] | 965 | if (remote_connected()) { |
| 966 | dlog(1, "already connected, assuming already reported\n"); |
| 967 | return; |
| 968 | } |
| 969 | |
| 970 | VG_(umsg)("(action on fatal signal) vgdb me ... \n"); |
| 971 | |
| 972 | /* indicate to gdbserver that there is a signal */ |
philippe | b301469 | 2015-05-17 13:38:25 +0000 | [diff] [blame] | 973 | gdbserver_signal_encountered (info); |
philippe | 2d1f256 | 2014-09-19 08:57:29 +0000 | [diff] [blame] | 974 | |
| 975 | /* let gdbserver do some work, e.g. show the signal to the user */ |
| 976 | call_gdbserver (tid, signal_reason); |
| 977 | |
| 978 | } |
| 979 | |
philippe | b301469 | 2015-05-17 13:38:25 +0000 | [diff] [blame] | 980 | Bool VG_(gdbserver_report_signal) (vki_siginfo_t *info, ThreadId tid) |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 981 | { |
philippe | b301469 | 2015-05-17 13:38:25 +0000 | [diff] [blame] | 982 | dlog_signal("VG_(gdbserver_report_signal)", info, tid); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 983 | |
| 984 | /* if gdbserver is currently not connected, then signal |
| 985 | is to be given to the process */ |
| 986 | if (!remote_connected()) { |
sewardj | b2572b5 | 2011-06-26 09:36:38 +0000 | [diff] [blame] | 987 | dlog(1, "not connected => pass\n"); |
| 988 | return True; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 989 | } |
sewardj | b2572b5 | 2011-06-26 09:36:38 +0000 | [diff] [blame] | 990 | /* if gdb has informed gdbserver that this signal can be |
| 991 | passed directly without informing gdb, then signal is |
| 992 | to be given to the process. */ |
philippe | b301469 | 2015-05-17 13:38:25 +0000 | [diff] [blame] | 993 | if (pass_signals[target_signal_from_host(info->si_signo)]) { |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 994 | dlog(1, "pass_signals => pass\n"); |
sewardj | b2572b5 | 2011-06-26 09:36:38 +0000 | [diff] [blame] | 995 | return True; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 996 | } |
| 997 | |
| 998 | /* indicate to gdbserver that there is a signal */ |
philippe | b301469 | 2015-05-17 13:38:25 +0000 | [diff] [blame] | 999 | gdbserver_signal_encountered (info); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1000 | |
philippe | b301469 | 2015-05-17 13:38:25 +0000 | [diff] [blame] | 1001 | /* let gdbserver do some work, e.g. show the signal to the user. |
| 1002 | User can also decide to ignore the signal or change the signal. */ |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1003 | call_gdbserver (tid, signal_reason); |
| 1004 | |
| 1005 | /* ask gdbserver what is the final decision */ |
philippe | b301469 | 2015-05-17 13:38:25 +0000 | [diff] [blame] | 1006 | if (gdbserver_deliver_signal (info)) { |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1007 | dlog(1, "gdbserver deliver signal\n"); |
| 1008 | return True; |
| 1009 | } else { |
| 1010 | dlog(1, "gdbserver ignore signal\n"); |
| 1011 | return False; |
| 1012 | } |
| 1013 | } |
| 1014 | |
Elliott Hughes | a0664b9 | 2017-04-18 17:46:52 -0700 | [diff] [blame] | 1015 | Bool catching_syscalls = False; // True if catching all or some syscalls. |
| 1016 | /* If catching_syscalls is True, then syscalls_to_catch_size == 0 means |
| 1017 | to catch all syscalls. Otherwise, it is the size of the syscalls_to_catch |
| 1018 | array. */ |
| 1019 | Int syscalls_to_catch_size = 0; |
| 1020 | Int *syscalls_to_catch; |
| 1021 | static Bool catch_this_syscall (Int sysno) |
| 1022 | { |
| 1023 | Int i; |
| 1024 | |
| 1025 | if (syscalls_to_catch_size == 0) |
| 1026 | return True; |
| 1027 | |
| 1028 | for (i = 0; i < syscalls_to_catch_size; i++) |
| 1029 | if (syscalls_to_catch[i] == sysno) |
| 1030 | return True; |
| 1031 | |
| 1032 | return False; |
| 1033 | } |
| 1034 | |
| 1035 | void VG_(gdbserver_report_syscall) (Bool before, UWord sysno, ThreadId tid) |
| 1036 | { |
| 1037 | dlog(4, "VG_(gdbserver_report_syscall) before %d sysno %lu tid %d\n", |
| 1038 | before, sysno, tid); |
| 1039 | |
| 1040 | if (UNLIKELY(catching_syscalls)) { |
| 1041 | if (!remote_connected()) { |
| 1042 | dlog(2, "not connected => no report\n"); |
| 1043 | } |
| 1044 | |
| 1045 | if (catch_this_syscall ((Int)sysno)) { |
| 1046 | /* let gdbserver do some work */ |
| 1047 | gdbserver_syscall_encountered (before, (Int)sysno); |
| 1048 | call_gdbserver (tid, signal_reason); |
| 1049 | } |
| 1050 | } |
| 1051 | } |
| 1052 | |
philippe | 0447bbd | 2012-10-17 21:32:03 +0000 | [diff] [blame] | 1053 | void VG_(gdbserver_exit) (ThreadId tid, VgSchedReturnCode tids_schedretcode) |
| 1054 | { |
florian | 654ea86 | 2015-08-06 12:11:33 +0000 | [diff] [blame] | 1055 | dlog(1, "VG core calling VG_(gdbserver_exit) tid %u will exit\n", tid); |
philippe | 0447bbd | 2012-10-17 21:32:03 +0000 | [diff] [blame] | 1056 | if (remote_connected()) { |
| 1057 | /* Make sure vgdb knows we are about to die and why. */ |
| 1058 | switch(tids_schedretcode) { |
| 1059 | case VgSrc_None: |
| 1060 | vg_assert (0); |
| 1061 | case VgSrc_ExitThread: |
| 1062 | case VgSrc_ExitProcess: |
Elliott Hughes | a0664b9 | 2017-04-18 17:46:52 -0700 | [diff] [blame] | 1063 | gdbserver_process_exit_encountered |
| 1064 | ('W', VG_(threads)[tid].os_state.exitcode); |
philippe | 0447bbd | 2012-10-17 21:32:03 +0000 | [diff] [blame] | 1065 | call_gdbserver (tid, exit_reason); |
| 1066 | break; |
| 1067 | case VgSrc_FatalSig: |
Elliott Hughes | a0664b9 | 2017-04-18 17:46:52 -0700 | [diff] [blame] | 1068 | gdbserver_process_exit_encountered |
| 1069 | ('X', VG_(threads)[tid].os_state.fatalsig); |
philippe | 0447bbd | 2012-10-17 21:32:03 +0000 | [diff] [blame] | 1070 | call_gdbserver (tid, exit_reason); |
| 1071 | break; |
| 1072 | default: |
| 1073 | vg_assert(0); |
| 1074 | } |
| 1075 | } else { |
| 1076 | dlog(1, "not connected\n"); |
| 1077 | } |
| 1078 | |
| 1079 | /* Tear down the connection if it still exists. */ |
| 1080 | VG_(gdbserver) (0); |
| 1081 | } |
| 1082 | |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1083 | // Check if single_stepping or if there is a break requested at iaddr. |
| 1084 | // If yes, call debugger |
| 1085 | VG_REGPARM(1) |
| 1086 | void VG_(helperc_CallDebugger) ( HWord iaddr ) |
| 1087 | { |
| 1088 | GS_Address* g; |
| 1089 | |
| 1090 | // For Vg_VgdbFull, after a fork, we might have calls to this helper |
| 1091 | // while gdbserver is not yet initialized. |
| 1092 | if (!gdbserver_called) |
| 1093 | return; |
| 1094 | |
| 1095 | if (valgrind_single_stepping() || |
sewardj | 6b7357b | 2011-05-27 13:23:44 +0000 | [diff] [blame] | 1096 | ((g = VG_(HT_lookup) (gs_addresses, (UWord)HT_addr(iaddr))) && |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1097 | (g->kind == GS_break))) { |
sewardj | 6b7357b | 2011-05-27 13:23:44 +0000 | [diff] [blame] | 1098 | if (iaddr == HT_addr(ignore_this_break_once)) { |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1099 | dlog(1, "ignoring ignore_this_break_once %s\n", |
| 1100 | sym(ignore_this_break_once, /* is_code */ True)); |
| 1101 | ignore_this_break_once = 0; |
| 1102 | } else { |
| 1103 | call_gdbserver (VG_(get_running_tid)(), break_reason); |
| 1104 | } |
| 1105 | } |
| 1106 | } |
| 1107 | |
| 1108 | /* software_breakpoint support --------------------------------------*/ |
| 1109 | /* When a block is instrumented for gdbserver, single step and breaks |
| 1110 | will be obeyed in this block. However, if a jump to another block |
| 1111 | is executed while single_stepping is active, we must ensure that |
| 1112 | this block is also instrumented. For this, when a block is |
| 1113 | instrumented for gdbserver while single_stepping, the target of all |
| 1114 | the Jump instructions in this block will be checked to verify if |
| 1115 | the block is already instrumented for gdbserver. The below will |
| 1116 | ensure that if not already instrumented for gdbserver, the target |
| 1117 | block translation containing addr will be invalidated. The list of |
| 1118 | gdbserved Addr will also be kept so that translations can be |
| 1119 | dropped automatically by gdbserver when going out of single step |
| 1120 | mode. |
| 1121 | |
| 1122 | Call the below at translation time if the jump target is a constant. |
| 1123 | Otherwise, rather use VG_(add_stmt_call_invalidate_if_not_gdbserved). |
| 1124 | |
| 1125 | To instrument the target exit statement, you can call |
| 1126 | VG_(add_stmt_call_invalidate_exit_target_if_not_gdbserved) rather |
| 1127 | than check the kind of target exit. */ |
| 1128 | static void VG_(invalidate_if_not_gdbserved) (Addr addr) |
| 1129 | { |
| 1130 | if (valgrind_single_stepping()) |
| 1131 | invalidate_if_jump_not_yet_gdbserved |
| 1132 | (addr, "gdbserver target jump (instrument)"); |
| 1133 | } |
| 1134 | |
| 1135 | // same as VG_(invalidate_if_not_gdbserved) but is intended to be called |
| 1136 | // at runtime (only difference is the invalidate reason which traces |
| 1137 | // it is at runtime) |
| 1138 | VG_REGPARM(1) |
| 1139 | void VG_(helperc_invalidate_if_not_gdbserved) ( Addr addr ) |
| 1140 | { |
| 1141 | if (valgrind_single_stepping()) |
| 1142 | invalidate_if_jump_not_yet_gdbserved |
| 1143 | (addr, "gdbserver target jump (runtime)"); |
| 1144 | } |
| 1145 | |
| 1146 | static void VG_(add_stmt_call_invalidate_if_not_gdbserved) |
| 1147 | ( IRSB* sb_in, |
florian | 3c0c947 | 2014-09-24 12:06:55 +0000 | [diff] [blame] | 1148 | const VexGuestLayout* layout, |
| 1149 | const VexGuestExtents* vge, |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1150 | IRTemp jmp, |
| 1151 | IRSB* irsb) |
| 1152 | { |
| 1153 | |
| 1154 | void* fn; |
florian | 1636d33 | 2012-11-15 04:27:04 +0000 | [diff] [blame] | 1155 | const HChar* nm; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1156 | IRExpr** args; |
| 1157 | Int nargs; |
| 1158 | IRDirty* di; |
| 1159 | |
| 1160 | fn = &VG_(helperc_invalidate_if_not_gdbserved); |
| 1161 | nm = "VG_(helperc_invalidate_if_not_gdbserved)"; |
| 1162 | args = mkIRExprVec_1(IRExpr_RdTmp (jmp)); |
| 1163 | nargs = 1; |
| 1164 | |
| 1165 | di = unsafeIRDirty_0_N( nargs/*regparms*/, nm, |
| 1166 | VG_(fnptr_to_fnentry)( fn ), args ); |
| 1167 | |
| 1168 | di->nFxState = 0; |
| 1169 | |
| 1170 | addStmtToIRSB(irsb, IRStmt_Dirty(di)); |
| 1171 | } |
| 1172 | |
| 1173 | /* software_breakpoint support --------------------------------------*/ |
| 1174 | /* If a tool wants to allow gdbserver to do something at Addr, then |
| 1175 | VG_(add_stmt_call_gdbserver) will add in IRSB a call to a helper |
| 1176 | function. This helper function will check if the process must be |
| 1177 | stopped at the instruction Addr: either there is a break at Addr or |
| 1178 | the process is being single-stepped. Typical usage of the below is to |
| 1179 | instrument an Ist_IMark to allow the debugger to interact at any |
| 1180 | instruction being executed. As soon as there is one break in a block, |
| 1181 | then to allow single stepping in this block (and possible insertions |
| 1182 | of other breaks in the same sb_in while the process is stopped), a |
| 1183 | debugger statement will be inserted for all instructions of a block. */ |
| 1184 | static void VG_(add_stmt_call_gdbserver) |
| 1185 | (IRSB* sb_in, /* block being translated */ |
florian | 3c0c947 | 2014-09-24 12:06:55 +0000 | [diff] [blame] | 1186 | const VexGuestLayout* layout, |
| 1187 | const VexGuestExtents* vge, |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1188 | IRType gWordTy, IRType hWordTy, |
sewardj | 6b7357b | 2011-05-27 13:23:44 +0000 | [diff] [blame] | 1189 | Addr iaddr, /* Addr of instruction being instrumented */ |
| 1190 | UChar delta, /* delta to add to iaddr to obtain IP */ |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1191 | IRSB* irsb) /* irsb block to which call is added */ |
| 1192 | { |
| 1193 | void* fn; |
florian | 1636d33 | 2012-11-15 04:27:04 +0000 | [diff] [blame] | 1194 | const HChar* nm; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1195 | IRExpr** args; |
| 1196 | Int nargs; |
| 1197 | IRDirty* di; |
| 1198 | |
| 1199 | /* first store the address in the program counter so that the check |
| 1200 | done by VG_(helperc_CallDebugger) will be based on the correct |
| 1201 | program counter. We might make this more efficient by rather |
| 1202 | searching for assignement to program counter and instrumenting |
| 1203 | that but the below is easier and I guess that the optimiser will |
| 1204 | remove the redundant store. And in any case, when debugging a |
| 1205 | piece of code, the efficiency requirement is not critical: very |
| 1206 | few blocks will be instrumented for debugging. */ |
sewardj | 6b7357b | 2011-05-27 13:23:44 +0000 | [diff] [blame] | 1207 | |
| 1208 | /* For platforms on which the IP can differ from the addr of the instruction |
| 1209 | being executed, we need to add the delta to obtain the IP. |
| 1210 | This IP will be given to gdb (e.g. if a breakpoint is put at iaddr). |
| 1211 | |
| 1212 | For ARM, this delta will ensure that the thumb bit is set in the |
| 1213 | IP when executing thumb code. gdb uses this thumb bit a.o. |
| 1214 | to properly guess the next IP for the 'step' and 'stepi' commands. */ |
| 1215 | vg_assert(delta <= 1); |
| 1216 | addStmtToIRSB(irsb, IRStmt_Put(layout->offset_IP , |
| 1217 | mkIRExpr_HWord(iaddr + (Addr)delta))); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1218 | |
| 1219 | fn = &VG_(helperc_CallDebugger); |
| 1220 | nm = "VG_(helperc_CallDebugger)"; |
| 1221 | args = mkIRExprVec_1(mkIRExpr_HWord (iaddr)); |
| 1222 | nargs = 1; |
| 1223 | |
| 1224 | di = unsafeIRDirty_0_N( nargs/*regparms*/, nm, |
| 1225 | VG_(fnptr_to_fnentry)( fn ), args ); |
| 1226 | |
| 1227 | /* Note: in fact, a debugger call can read whatever register |
| 1228 | or memory. It can also write whatever register or memory. |
| 1229 | So, in theory, we have to indicate the whole universe |
| 1230 | can be read and modified. It is however not critical |
| 1231 | to indicate precisely what is being read/written |
| 1232 | as such indications are needed for tool error detection |
| 1233 | and we do not want to have errors being detected for |
| 1234 | gdb interactions. */ |
| 1235 | |
| 1236 | di->nFxState = 2; |
sewardj | 2eecb74 | 2012-06-01 16:11:41 +0000 | [diff] [blame] | 1237 | di->fxState[0].fx = Ifx_Read; |
| 1238 | di->fxState[0].offset = layout->offset_SP; |
| 1239 | di->fxState[0].size = layout->sizeof_SP; |
| 1240 | di->fxState[0].nRepeats = 0; |
| 1241 | di->fxState[0].repeatLen = 0; |
| 1242 | di->fxState[1].fx = Ifx_Modify; |
| 1243 | di->fxState[1].offset = layout->offset_IP; |
| 1244 | di->fxState[1].size = layout->sizeof_IP; |
| 1245 | di->fxState[1].nRepeats = 0; |
| 1246 | di->fxState[1].repeatLen = 0; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1247 | |
| 1248 | addStmtToIRSB(irsb, IRStmt_Dirty(di)); |
| 1249 | |
| 1250 | } |
| 1251 | |
| 1252 | |
| 1253 | /* Invalidate the target of the exit if needed: |
| 1254 | If target is constant, it is invalidated at translation time. |
| 1255 | Otherwise, a call to a helper function is generated to invalidate |
| 1256 | the translation at run time. |
| 1257 | The below is thus calling either VG_(invalidate_if_not_gdbserved) |
| 1258 | or VG_(add_stmt_call_invalidate_if_not_gdbserved). */ |
| 1259 | static void VG_(add_stmt_call_invalidate_exit_target_if_not_gdbserved) |
| 1260 | (IRSB* sb_in, |
florian | 3c0c947 | 2014-09-24 12:06:55 +0000 | [diff] [blame] | 1261 | const VexGuestLayout* layout, |
| 1262 | const VexGuestExtents* vge, |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1263 | IRType gWordTy, |
| 1264 | IRSB* irsb) |
| 1265 | { |
| 1266 | if (sb_in->next->tag == Iex_Const) { |
| 1267 | VG_(invalidate_if_not_gdbserved) (gWordTy == Ity_I64 ? |
| 1268 | sb_in->next->Iex.Const.con->Ico.U64 |
| 1269 | : sb_in->next->Iex.Const.con->Ico.U32); |
| 1270 | } else if (sb_in->next->tag == Iex_RdTmp) { |
| 1271 | VG_(add_stmt_call_invalidate_if_not_gdbserved) |
| 1272 | (sb_in, layout, vge, sb_in->next->Iex.RdTmp.tmp, irsb); |
| 1273 | } else { |
| 1274 | vg_assert (0); /* unexpected expression tag in exit. */ |
| 1275 | } |
| 1276 | } |
| 1277 | |
| 1278 | IRSB* VG_(instrument_for_gdbserver_if_needed) |
| 1279 | (IRSB* sb_in, |
florian | 3c0c947 | 2014-09-24 12:06:55 +0000 | [diff] [blame] | 1280 | const VexGuestLayout* layout, |
| 1281 | const VexGuestExtents* vge, |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1282 | IRType gWordTy, IRType hWordTy) |
| 1283 | { |
| 1284 | IRSB* sb_out; |
| 1285 | Int i; |
| 1286 | const VgVgdb instr_needed = VG_(gdbserver_instrumentation_needed) (vge); |
| 1287 | |
| 1288 | if (instr_needed == Vg_VgdbNo) |
| 1289 | return sb_in; |
| 1290 | |
| 1291 | |
| 1292 | /* here, we need to instrument for gdbserver */ |
| 1293 | sb_out = deepCopyIRSBExceptStmts(sb_in); |
| 1294 | |
| 1295 | for (i = 0; i < sb_in->stmts_used; i++) { |
| 1296 | IRStmt* st = sb_in->stmts[i]; |
| 1297 | |
| 1298 | if (!st || st->tag == Ist_NoOp) continue; |
| 1299 | |
| 1300 | if (st->tag == Ist_Exit && instr_needed == Vg_VgdbYes) { |
| 1301 | VG_(invalidate_if_not_gdbserved) |
| 1302 | (hWordTy == Ity_I64 ? |
| 1303 | st->Ist.Exit.dst->Ico.U64 : |
| 1304 | st->Ist.Exit.dst->Ico.U32); |
| 1305 | } |
| 1306 | addStmtToIRSB( sb_out, st ); |
| 1307 | if (st->tag == Ist_IMark) { |
| 1308 | /* For an Ist_Mark, add a call to debugger. */ |
| 1309 | switch (instr_needed) { |
| 1310 | case Vg_VgdbNo: vg_assert (0); |
| 1311 | case Vg_VgdbYes: |
| 1312 | case Vg_VgdbFull: |
| 1313 | VG_(add_stmt_call_gdbserver) ( sb_in, layout, vge, |
| 1314 | gWordTy, hWordTy, |
| 1315 | st->Ist.IMark.addr, |
sewardj | 6b7357b | 2011-05-27 13:23:44 +0000 | [diff] [blame] | 1316 | st->Ist.IMark.delta, |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1317 | sb_out); |
| 1318 | /* There is an optimisation possible here for Vg_VgdbFull: |
| 1319 | Put a guard ensuring we only call gdbserver if 'FullCallNeeded'. |
| 1320 | FullCallNeeded would be set to 1 we have just switched on |
| 1321 | Single Stepping or have just encountered a watchpoint |
| 1322 | or have just inserted a breakpoint. |
| 1323 | (as gdb by default removes and re-insert breakpoints), we would |
| 1324 | need to also implement the notion of 'breakpoint pending removal' |
| 1325 | to remove at the next 'continue/step' packet. */ |
| 1326 | break; |
| 1327 | default: vg_assert (0); |
| 1328 | } |
| 1329 | } |
| 1330 | } |
| 1331 | |
| 1332 | if (instr_needed == Vg_VgdbYes) { |
| 1333 | VG_(add_stmt_call_invalidate_exit_target_if_not_gdbserved) (sb_in, |
| 1334 | layout, vge, |
| 1335 | gWordTy, |
| 1336 | sb_out); |
| 1337 | } |
| 1338 | |
| 1339 | return sb_out; |
| 1340 | } |
| 1341 | |
| 1342 | struct mon_out_buf { |
florian | 1636d33 | 2012-11-15 04:27:04 +0000 | [diff] [blame] | 1343 | HChar buf[DATASIZ+1]; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1344 | int next; |
| 1345 | UInt ret; |
| 1346 | }; |
| 1347 | |
| 1348 | static void mon_out (HChar c, void *opaque) |
| 1349 | { |
| 1350 | struct mon_out_buf *b = (struct mon_out_buf *) opaque; |
| 1351 | b->ret++; |
| 1352 | b->buf[b->next] = c; |
| 1353 | b->next++; |
| 1354 | if (b->next == DATASIZ) { |
| 1355 | b->buf[b->next] = '\0'; |
| 1356 | monitor_output(b->buf); |
| 1357 | b->next = 0; |
| 1358 | } |
| 1359 | } |
| 1360 | UInt VG_(gdb_printf) ( const HChar *format, ... ) |
| 1361 | { |
| 1362 | struct mon_out_buf b; |
| 1363 | |
| 1364 | b.next = 0; |
| 1365 | b.ret = 0; |
| 1366 | |
| 1367 | va_list vargs; |
| 1368 | va_start(vargs, format); |
| 1369 | VG_(vcbprintf) (mon_out, &b, format, vargs); |
| 1370 | va_end(vargs); |
| 1371 | |
| 1372 | if (b.next > 0) { |
| 1373 | b.buf[b.next] = '\0'; |
| 1374 | monitor_output(b.buf); |
| 1375 | } |
| 1376 | return b.ret; |
| 1377 | } |
| 1378 | |
florian | 6bd9dc1 | 2012-11-23 16:17:43 +0000 | [diff] [blame] | 1379 | Int VG_(keyword_id) (const HChar* keywords, const HChar* input_word, |
| 1380 | kwd_report_error report) |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1381 | { |
| 1382 | const Int il = (input_word == NULL ? 0 : VG_(strlen) (input_word)); |
florian | 19f91bb | 2012-11-10 22:29:54 +0000 | [diff] [blame] | 1383 | HChar iw[il+1]; |
| 1384 | HChar kwds[VG_(strlen)(keywords)+1]; |
| 1385 | HChar *kwdssaveptr; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1386 | |
florian | 1636d33 | 2012-11-15 04:27:04 +0000 | [diff] [blame] | 1387 | HChar* kw; /* current keyword, its length, its position */ |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1388 | Int kwl; |
| 1389 | Int kpos = -1; |
| 1390 | |
| 1391 | Int pass; |
| 1392 | /* pass 0 = search, optional pass 1 = output message multiple matches */ |
| 1393 | |
| 1394 | Int pass1needed = 0; |
| 1395 | |
| 1396 | Int partial_match = -1; |
| 1397 | Int full_match = -1; |
| 1398 | |
| 1399 | if (input_word == NULL) { |
| 1400 | iw[0] = 0; |
| 1401 | partial_match = 0; /* to force an empty string to cause an error */ |
| 1402 | } else { |
| 1403 | VG_(strcpy) (iw, input_word); |
| 1404 | } |
| 1405 | |
| 1406 | for (pass = 0; pass < 2; pass++) { |
| 1407 | VG_(strcpy) (kwds, keywords); |
| 1408 | if (pass == 1) |
| 1409 | VG_(gdb_printf) ("%s can match", |
florian | 1636d33 | 2012-11-15 04:27:04 +0000 | [diff] [blame] | 1410 | (il == 0 ? "<empty string>" : iw)); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1411 | for (kw = VG_(strtok_r) (kwds, " ", &kwdssaveptr); |
| 1412 | kw != NULL; |
| 1413 | kw = VG_(strtok_r) (NULL, " ", &kwdssaveptr)) { |
| 1414 | kwl = VG_(strlen) (kw); |
| 1415 | kpos++; |
| 1416 | |
| 1417 | if (il > kwl) { |
| 1418 | ; /* ishtar !~ is */ |
| 1419 | } else if (il == kwl) { |
| 1420 | if (VG_(strcmp) (kw, iw) == 0) { |
| 1421 | /* exact match */ |
| 1422 | if (pass == 1) |
| 1423 | VG_(gdb_printf) (" %s", kw); |
| 1424 | if (full_match != -1) |
| 1425 | pass1needed++; |
| 1426 | full_match = kpos; |
| 1427 | } |
| 1428 | } else { |
| 1429 | /* il < kwl */ |
| 1430 | if (VG_(strncmp) (iw, kw, il) == 0) { |
| 1431 | /* partial match */ |
| 1432 | if (pass == 1) |
| 1433 | VG_(gdb_printf) (" %s", kw); |
| 1434 | if (partial_match != -1) |
| 1435 | pass1needed++; |
| 1436 | partial_match = kpos; |
| 1437 | } |
| 1438 | } |
| 1439 | } |
| 1440 | /* check for success or for no match at all */ |
| 1441 | if (pass1needed == 0) { |
| 1442 | if (full_match != -1) { |
| 1443 | return full_match; |
| 1444 | } else { |
| 1445 | if (report == kwd_report_all && partial_match == -1) { |
| 1446 | VG_(gdb_printf) ("%s does not match any of '%s'\n", |
| 1447 | iw, keywords); |
| 1448 | } |
| 1449 | return partial_match; |
| 1450 | } |
| 1451 | } |
| 1452 | |
| 1453 | /* here we have duplicated match error */ |
| 1454 | if (pass == 1 || report == kwd_report_none) { |
| 1455 | if (report != kwd_report_none) { |
| 1456 | VG_(gdb_printf) ("\n"); |
| 1457 | } |
| 1458 | if (partial_match != -1 || full_match != -1) |
| 1459 | return -2; |
| 1460 | else |
| 1461 | return -1; |
| 1462 | } |
| 1463 | } |
| 1464 | /* UNREACHED */ |
| 1465 | vg_assert (0); |
| 1466 | } |
| 1467 | |
| 1468 | /* True if string can be a 0x number */ |
florian | 1636d33 | 2012-11-15 04:27:04 +0000 | [diff] [blame] | 1469 | static Bool is_zero_x (const HChar *s) |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1470 | { |
| 1471 | if (strlen (s) >= 3 && s[0] == '0' && s[1] == 'x') |
| 1472 | return True; |
| 1473 | else |
| 1474 | return False; |
| 1475 | } |
| 1476 | |
| 1477 | /* True if string can be a 0b number */ |
florian | 1636d33 | 2012-11-15 04:27:04 +0000 | [diff] [blame] | 1478 | static Bool is_zero_b (const HChar *s) |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1479 | { |
| 1480 | if (strlen (s) >= 3 && s[0] == '0' && s[1] == 'b') |
| 1481 | return True; |
| 1482 | else |
| 1483 | return False; |
| 1484 | } |
| 1485 | |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 1486 | Bool VG_(strtok_get_address_and_size) (Addr* address, |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1487 | SizeT* szB, |
florian | 19f91bb | 2012-11-10 22:29:54 +0000 | [diff] [blame] | 1488 | HChar **ssaveptr) |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1489 | { |
florian | 19f91bb | 2012-11-10 22:29:54 +0000 | [diff] [blame] | 1490 | HChar* wa; |
| 1491 | HChar* ws; |
| 1492 | HChar* endptr; |
| 1493 | const HChar *ppc; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1494 | |
| 1495 | wa = VG_(strtok_r) (NULL, " ", ssaveptr); |
| 1496 | ppc = wa; |
| 1497 | if (ppc == NULL || !VG_(parse_Addr) (&ppc, address)) { |
| 1498 | VG_(gdb_printf) ("missing or malformed address\n"); |
| 1499 | *address = (Addr) 0; |
| 1500 | *szB = 0; |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 1501 | return False; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1502 | } |
| 1503 | ws = VG_(strtok_r) (NULL, " ", ssaveptr); |
| 1504 | if (ws == NULL) { |
| 1505 | /* Do nothing, i.e. keep current value of szB. */ ; |
| 1506 | } else if (is_zero_x (ws)) { |
| 1507 | *szB = VG_(strtoull16) (ws, &endptr); |
| 1508 | } else if (is_zero_b (ws)) { |
| 1509 | Int j; |
florian | 1636d33 | 2012-11-15 04:27:04 +0000 | [diff] [blame] | 1510 | HChar *parsews = ws; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1511 | Int n_bits = VG_(strlen) (ws) - 2; |
| 1512 | *szB = 0; |
| 1513 | ws = NULL; // assume the below loop gives a correct nr. |
| 1514 | for (j = 0; j < n_bits; j++) { |
| 1515 | if ('0' == parsews[j+2]) { /* do nothing */ } |
| 1516 | else if ('1' == parsews[j+2]) *szB |= (1 << (n_bits-j-1)); |
| 1517 | else { |
| 1518 | /* report malformed binary integer */ |
| 1519 | ws = parsews; |
| 1520 | endptr = ws + j + 2; |
| 1521 | break; |
| 1522 | } |
| 1523 | } |
| 1524 | } else { |
| 1525 | *szB = VG_(strtoull10) (ws, &endptr); |
| 1526 | } |
| 1527 | |
| 1528 | if (ws != NULL && *endptr != '\0') { |
| 1529 | VG_(gdb_printf) ("malformed integer, expecting " |
| 1530 | "hex 0x..... or dec ...... or binary .....b\n"); |
| 1531 | *address = (Addr) 0; |
| 1532 | *szB = 0; |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 1533 | return False; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1534 | } |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 1535 | return True; |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1536 | } |
| 1537 | |
| 1538 | void VG_(gdbserver_status_output)(void) |
| 1539 | { |
| 1540 | const int nr_gdbserved_addresses |
| 1541 | = (gs_addresses == NULL ? -1 : VG_(HT_count_nodes) (gs_addresses)); |
| 1542 | const int nr_watchpoints |
philippe | 0972443 | 2012-06-14 19:56:20 +0000 | [diff] [blame] | 1543 | = (gs_watches == NULL ? -1 : (int) VG_(sizeXA) (gs_watches)); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1544 | remote_utils_output_status(); |
| 1545 | VG_(umsg) |
| 1546 | ("nr of calls to gdbserver: %d\n" |
| 1547 | "single stepping %d\n" |
florian | 654ea86 | 2015-08-06 12:11:33 +0000 | [diff] [blame] | 1548 | "interrupts intr_tid %u gs_non_busy %d gs_busy %d tid_non_intr %d\n" |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1549 | "gdbserved addresses %d (-1 = not initialized)\n" |
| 1550 | "watchpoints %d (-1 = not initialized)\n" |
philippe | 180a750 | 2014-04-20 13:41:10 +0000 | [diff] [blame] | 1551 | "vgdb-error %d\n" |
| 1552 | "hostvisibility %s\n", |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1553 | gdbserver_called, |
| 1554 | valgrind_single_stepping(), |
| 1555 | |
| 1556 | vgdb_interrupted_tid, |
| 1557 | interrupts_non_busy, |
| 1558 | interrupts_while_busy, |
| 1559 | interrupts_non_interruptible, |
| 1560 | |
| 1561 | nr_gdbserved_addresses, |
| 1562 | nr_watchpoints, |
philippe | 180a750 | 2014-04-20 13:41:10 +0000 | [diff] [blame] | 1563 | VG_(dyn_vgdb_error), |
| 1564 | hostvisibility ? "yes" : "no"); |
sewardj | 3b29048 | 2011-05-06 21:02:55 +0000 | [diff] [blame] | 1565 | } |