philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 1 | |
| 2 | /*--------------------------------------------------------------------*/ |
| 3 | /*--- Obtaining information about an address. ---*/ |
| 4 | /*--- m_addrinfo.c ---*/ |
| 5 | /*--------------------------------------------------------------------*/ |
| 6 | |
| 7 | /* |
| 8 | This file is part of Valgrind, a dynamic binary instrumentation |
| 9 | framework. |
| 10 | |
Elliott Hughes | ed39800 | 2017-06-21 14:41:24 -0700 | [diff] [blame] | 11 | Copyright (C) 2008-2017 OpenWorks Ltd |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 12 | info@open-works.co.uk |
| 13 | |
| 14 | This program is free software; you can redistribute it and/or |
| 15 | modify it under the terms of the GNU General Public License as |
| 16 | published by the Free Software Foundation; either version 2 of the |
| 17 | License, or (at your option) any later version. |
| 18 | |
| 19 | This program is distributed in the hope that it will be useful, but |
| 20 | WITHOUT ANY WARRANTY; without even the implied warranty of |
| 21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 22 | General Public License for more details. |
| 23 | |
| 24 | You should have received a copy of the GNU General Public License |
| 25 | along with this program; if not, write to the Free Software |
| 26 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 27 | 02111-1307, USA. |
| 28 | |
| 29 | The GNU General Public License is contained in the file COPYING. |
| 30 | */ |
| 31 | |
| 32 | #include "pub_core_basics.h" |
philippe | d0da968 | 2014-12-28 17:30:22 +0000 | [diff] [blame] | 33 | #include "pub_core_clientstate.h" |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 34 | #include "pub_core_libcassert.h" |
| 35 | #include "pub_core_libcbase.h" |
| 36 | #include "pub_core_libcprint.h" |
| 37 | #include "pub_core_xarray.h" |
| 38 | #include "pub_core_debuginfo.h" |
| 39 | #include "pub_core_execontext.h" |
| 40 | #include "pub_core_addrinfo.h" |
| 41 | #include "pub_core_mallocfree.h" |
| 42 | #include "pub_core_machine.h" |
| 43 | #include "pub_core_options.h" |
philippe | 7e3b3f2 | 2014-08-31 22:27:19 +0000 | [diff] [blame] | 44 | #include "pub_core_threadstate.h" |
philippe | 18d6f4e | 2014-05-22 23:48:24 +0000 | [diff] [blame] | 45 | #include "pub_core_stacktrace.h" |
philippe | 7e3b3f2 | 2014-08-31 22:27:19 +0000 | [diff] [blame] | 46 | #include "pub_core_stacks.h" |
| 47 | #include "pub_core_aspacemgr.h" |
| 48 | |
| 49 | /* Returns the tid whose stack includes the address a. |
| 50 | If not found, returns VG_INVALID_THREADID. */ |
| 51 | static ThreadId find_tid_with_stack_containing (Addr a) |
| 52 | { |
| 53 | ThreadId tid; |
| 54 | Addr start, end; |
| 55 | |
| 56 | start = 0; |
| 57 | end = 0; |
| 58 | VG_(stack_limits)(a, &start, &end); |
| 59 | if (start == end) { |
| 60 | // No stack found |
| 61 | vg_assert (start == 0 && end == 0); |
| 62 | return VG_INVALID_THREADID; |
| 63 | } |
| 64 | |
| 65 | /* Stack limits found. Search the tid to which this stack belongs. */ |
| 66 | vg_assert (start <= a); |
| 67 | vg_assert (a <= end); |
| 68 | |
| 69 | /* The stack end (highest accessible byte) is for sure inside the 'active' |
| 70 | part of the stack of the searched tid. |
| 71 | So, scan all 'active' stacks with VG_(thread_stack_reset_iter) ... */ |
| 72 | { |
| 73 | Addr stack_min, stack_max; |
| 74 | |
| 75 | VG_(thread_stack_reset_iter)(&tid); |
| 76 | while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) { |
| 77 | if (stack_min <= end && end <= stack_max) |
| 78 | return tid; |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | /* We can arrive here if a stack was registered with wrong bounds |
| 83 | (e.g. end above the highest addressable byte) |
| 84 | and/or if the thread for the registered stack is dead, but |
| 85 | the stack was not unregistered. */ |
| 86 | return VG_INVALID_THREADID; |
| 87 | } |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 88 | |
| 89 | void VG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai ) |
| 90 | { |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 91 | VgSectKind sect; |
| 92 | |
| 93 | /* -- Perhaps the variable type/location data describes it? -- */ |
| 94 | ai->Addr.Variable.descr1 |
| 95 | = VG_(newXA)( VG_(malloc), "mc.da.descr1", |
| 96 | VG_(free), sizeof(HChar) ); |
| 97 | ai->Addr.Variable.descr2 |
| 98 | = VG_(newXA)( VG_(malloc), "mc.da.descr2", |
| 99 | VG_(free), sizeof(HChar) ); |
| 100 | |
| 101 | (void) VG_(get_data_description)( ai->Addr.Variable.descr1, |
| 102 | ai->Addr.Variable.descr2, a ); |
florian | ad4e979 | 2015-07-05 21:53:33 +0000 | [diff] [blame] | 103 | /* If there's nothing in descr1/2, free them. Why is it safe to |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 104 | VG_(indexXA) at zero here? Because VG_(get_data_description) |
| 105 | guarantees to zero terminate descr1/2 regardless of the outcome |
| 106 | of the call. So there's always at least one element in each XA |
| 107 | after the call. |
| 108 | */ |
| 109 | if (0 == VG_(strlen)( VG_(indexXA)( ai->Addr.Variable.descr1, 0 ))) { |
| 110 | VG_(deleteXA)( ai->Addr.Variable.descr1 ); |
| 111 | ai->Addr.Variable.descr1 = NULL; |
| 112 | } |
| 113 | if (0 == VG_(strlen)( VG_(indexXA)( ai->Addr.Variable.descr2, 0 ))) { |
| 114 | VG_(deleteXA)( ai->Addr.Variable.descr2 ); |
| 115 | ai->Addr.Variable.descr2 = NULL; |
| 116 | } |
| 117 | /* Assume (assert) that VG_(get_data_description) fills in descr1 |
| 118 | before it fills in descr2 */ |
| 119 | if (ai->Addr.Variable.descr1 == NULL) |
| 120 | vg_assert(ai->Addr.Variable.descr2 == NULL); |
| 121 | /* So did we get lucky? */ |
| 122 | if (ai->Addr.Variable.descr1 != NULL) { |
| 123 | ai->tag = Addr_Variable; |
| 124 | return; |
| 125 | } |
| 126 | /* -- Have a look at the low level data symbols - perhaps it's in |
| 127 | there. -- */ |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 128 | const HChar *name; |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 129 | if (VG_(get_datasym_and_offset)( |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 130 | a, &name, |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 131 | &ai->Addr.DataSym.offset )) { |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 132 | ai->Addr.DataSym.name = VG_(strdup)("mc.da.dsname", name); |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 133 | ai->tag = Addr_DataSym; |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 134 | return; |
| 135 | } |
| 136 | /* -- Perhaps it's on a thread's stack? -- */ |
philippe | 18d6f4e | 2014-05-22 23:48:24 +0000 | [diff] [blame] | 137 | { |
philippe | 7e3b3f2 | 2014-08-31 22:27:19 +0000 | [diff] [blame] | 138 | ThreadId tid; |
philippe | 18d6f4e | 2014-05-22 23:48:24 +0000 | [diff] [blame] | 139 | Addr stack_min, stack_max; |
| 140 | VG_(thread_stack_reset_iter)(&tid); |
| 141 | while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) { |
| 142 | if (stack_min - VG_STACK_REDZONE_SZB <= a && a <= stack_max) { |
| 143 | Addr ips[VG_(clo_backtrace_size)], |
| 144 | sps[VG_(clo_backtrace_size)]; |
| 145 | UInt n_frames; |
| 146 | UInt f; |
| 147 | |
| 148 | ai->tag = Addr_Stack; |
philippe | 0c9ac8d | 2014-07-18 00:03:58 +0000 | [diff] [blame] | 149 | VG_(initThreadInfo)(&ai->Addr.Stack.tinfo); |
| 150 | ai->Addr.Stack.tinfo.tid = tid; |
philippe | 18d6f4e | 2014-05-22 23:48:24 +0000 | [diff] [blame] | 151 | ai->Addr.Stack.IP = 0; |
| 152 | ai->Addr.Stack.frameNo = -1; |
philippe | 7e3b3f2 | 2014-08-31 22:27:19 +0000 | [diff] [blame] | 153 | ai->Addr.Stack.stackPos = StackPos_stacked; |
| 154 | ai->Addr.Stack.spoffset = 0; // Unused. |
philippe | 18d6f4e | 2014-05-22 23:48:24 +0000 | [diff] [blame] | 155 | /* It is on thread tid stack. Build a stacktrace, and |
| 156 | find the frame sp[f] .. sp[f+1] where the address is. |
| 157 | Store the found frameNo and the corresponding IP in |
| 158 | the description. |
| 159 | When description is printed, IP will be translated to |
| 160 | the function name containing IP. |
| 161 | Before accepting to describe addr with sp[f] .. sp[f+1], |
| 162 | we verify the sp looks sane: reasonably sized frame, |
| 163 | inside the stack. |
| 164 | We could check the ABI required alignment for sp (what is it?) |
| 165 | is respected, except for the innermost stack pointer ? */ |
| 166 | n_frames = VG_(get_StackTrace)( tid, ips, VG_(clo_backtrace_size), |
| 167 | sps, NULL, 0/*first_ip_delta*/ ); |
| 168 | for (f = 0; f < n_frames-1; f++) { |
| 169 | if (sps[f] <= a && a < sps[f+1] |
| 170 | && sps[f+1] - sps[f] <= 0x4000000 // 64 MB, arbitrary |
| 171 | && sps[f+1] <= stack_max |
| 172 | && sps[f] >= stack_min - VG_STACK_REDZONE_SZB) { |
| 173 | ai->Addr.Stack.frameNo = f; |
| 174 | ai->Addr.Stack.IP = ips[f]; |
| 175 | break; |
| 176 | } |
| 177 | } |
| 178 | return; |
| 179 | } |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 180 | } |
| 181 | } |
| 182 | |
| 183 | /* -- Maybe it is in one of the m_mallocfree.c arenas. -- */ |
| 184 | { |
| 185 | AddrArenaInfo aai; |
| 186 | VG_(describe_arena_addr) ( a, &aai ); |
| 187 | if (aai.name != NULL) { |
| 188 | ai->tag = Addr_Block; |
| 189 | if (aai.aid == VG_AR_CLIENT) |
| 190 | ai->Addr.Block.block_kind |
| 191 | = aai.free ? Block_ClientArenaFree : Block_ClientArenaMallocd; |
| 192 | else |
| 193 | ai->Addr.Block.block_kind |
| 194 | = aai.free |
| 195 | ? Block_ValgrindArenaFree : Block_ValgrindArenaMallocd; |
| 196 | ai->Addr.Block.block_desc = aai.name; |
| 197 | ai->Addr.Block.block_szB = aai.block_szB; |
| 198 | ai->Addr.Block.rwoffset = aai.rwoffset; |
| 199 | ai->Addr.Block.allocated_at = VG_(null_ExeContext)(); |
philippe | 0c9ac8d | 2014-07-18 00:03:58 +0000 | [diff] [blame] | 200 | VG_(initThreadInfo) (&ai->Addr.Block.alloc_tinfo); |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 201 | ai->Addr.Block.freed_at = VG_(null_ExeContext)(); |
| 202 | return; |
| 203 | } |
| 204 | } |
| 205 | |
| 206 | /* -- last ditch attempt at classification -- */ |
florian | e08950b | 2014-11-13 21:41:28 +0000 | [diff] [blame] | 207 | sect = VG_(DebugInfo_sect_kind)( &name, a); |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 208 | if (sect != Vg_SectUnknown) { |
| 209 | ai->tag = Addr_SectKind; |
philippe | dd23820 | 2015-03-21 20:55:36 +0000 | [diff] [blame] | 210 | ai->Addr.SectKind.objname = VG_(strdup)("mc.da.dsname", name); |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 211 | ai->Addr.SectKind.kind = sect; |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 212 | return; |
| 213 | } |
philippe | 7e3b3f2 | 2014-08-31 22:27:19 +0000 | [diff] [blame] | 214 | |
| 215 | /* -- and yet another last ditch attempt at classification -- */ |
| 216 | /* If the address is in a stack between the stack bottom (highest byte) |
| 217 | and the current stack ptr, it will have been already described above. |
| 218 | But maybe it is in a stack, but below the stack ptr (typical |
| 219 | for a 'use after return' or in the stack guard page (thread stack |
| 220 | too small). */ |
| 221 | { |
| 222 | ThreadId tid; |
philippe | d099e51 | 2014-09-02 22:20:14 +0000 | [diff] [blame] | 223 | StackPos stackPos = StackPos_stacked; |
| 224 | // Default init to StackPos_stacked, to silence gcc warning. |
Elliott Hughes | ed39800 | 2017-06-21 14:41:24 -0700 | [diff] [blame] | 225 | // We assert this value is overridden if a stack descr is produced. |
philippe | 7e3b3f2 | 2014-08-31 22:27:19 +0000 | [diff] [blame] | 226 | |
| 227 | // First try to find a tid with stack containing a |
| 228 | tid = find_tid_with_stack_containing (a); |
| 229 | if (tid != VG_INVALID_THREADID) { |
| 230 | /* Should be below stack pointer, as if it is >= SP, it |
| 231 | will have been described as StackPos_stacked above. */ |
| 232 | stackPos = StackPos_below_stack_ptr; |
| 233 | } else { |
| 234 | /* Try to find a stack with guard page containing a. |
| 235 | For this, check if a is in a page mapped without r, w and x. */ |
| 236 | const NSegment *seg = VG_(am_find_nsegment) (a); |
| 237 | if (seg != NULL && seg->kind == SkAnonC |
| 238 | && !seg->hasR && !seg->hasW && !seg->hasX) { |
| 239 | /* This looks a plausible guard page. Check if a is close to |
| 240 | the start of stack (lowest byte). */ |
| 241 | tid = find_tid_with_stack_containing (VG_PGROUNDUP(a+1)); |
| 242 | if (tid != VG_INVALID_THREADID) |
| 243 | stackPos = StackPos_guard_page; |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | if (tid != VG_INVALID_THREADID) { |
| 248 | ai->tag = Addr_Stack; |
| 249 | VG_(initThreadInfo)(&ai->Addr.Stack.tinfo); |
| 250 | ai->Addr.Stack.tinfo.tid = tid; |
| 251 | ai->Addr.Stack.IP = 0; |
| 252 | ai->Addr.Stack.frameNo = -1; |
philippe | d099e51 | 2014-09-02 22:20:14 +0000 | [diff] [blame] | 253 | vg_assert (stackPos != StackPos_stacked); |
philippe | 7e3b3f2 | 2014-08-31 22:27:19 +0000 | [diff] [blame] | 254 | ai->Addr.Stack.stackPos = stackPos; |
| 255 | vg_assert (a < VG_(get_SP)(tid)); |
| 256 | ai->Addr.Stack.spoffset = a - VG_(get_SP)(tid); |
| 257 | return; |
| 258 | } |
| 259 | } |
| 260 | |
philippe | f7ec77f | 2014-11-24 17:46:41 +0000 | [diff] [blame] | 261 | /* -- and yet another last ditch attempt at classification -- */ |
| 262 | /* Try to find a segment belonging to the client. */ |
| 263 | { |
| 264 | const NSegment *seg = VG_(am_find_nsegment) (a); |
philippe | d0da968 | 2014-12-28 17:30:22 +0000 | [diff] [blame] | 265 | |
| 266 | /* Special case to detect the brk data segment. */ |
| 267 | if (seg != NULL |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 268 | #if defined(VGO_solaris) |
| 269 | && (seg->kind == SkAnonC || seg->kind == SkFileC) |
| 270 | #else |
philippe | d0da968 | 2014-12-28 17:30:22 +0000 | [diff] [blame] | 271 | && seg->kind == SkAnonC |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 272 | #endif /* VGO_solaris */ |
philippe | d0da968 | 2014-12-28 17:30:22 +0000 | [diff] [blame] | 273 | && VG_(brk_limit) >= seg->start |
| 274 | && VG_(brk_limit) <= seg->end+1) { |
| 275 | /* Address a is in a Anon Client segment which contains |
| 276 | VG_(brk_limit). So, this segment is the brk data segment |
| 277 | as initimg-linux.c:setup_client_dataseg maps an anonymous |
| 278 | segment followed by a reservation, with one reservation |
| 279 | page that will never be used by syswrap-generic.c:do_brk, |
| 280 | when increasing VG_(brk_limit). |
| 281 | So, the brk data segment will never be merged with the |
| 282 | next segment, and so an address in that area will |
| 283 | either be in the brk data segment, or in the unmapped |
| 284 | part of the brk data segment reservation. */ |
| 285 | ai->tag = Addr_BrkSegment; |
| 286 | ai->Addr.BrkSegment.brk_limit = VG_(brk_limit); |
| 287 | return; |
| 288 | } |
| 289 | |
philippe | f7ec77f | 2014-11-24 17:46:41 +0000 | [diff] [blame] | 290 | if (seg != NULL |
| 291 | && (seg->kind == SkAnonC |
| 292 | || seg->kind == SkFileC |
| 293 | || seg->kind == SkShmC)) { |
| 294 | ai->tag = Addr_SegmentKind; |
| 295 | ai->Addr.SegmentKind.segkind = seg->kind; |
| 296 | ai->Addr.SegmentKind.filename = NULL; |
| 297 | if (seg->kind == SkFileC) |
florian | d3166c4 | 2015-01-24 00:02:19 +0000 | [diff] [blame] | 298 | ai->Addr.SegmentKind.filename |
| 299 | = VG_(strdup)("mc.da.skfname", VG_(am_get_filename)(seg)); |
philippe | f7ec77f | 2014-11-24 17:46:41 +0000 | [diff] [blame] | 300 | ai->Addr.SegmentKind.hasR = seg->hasR; |
| 301 | ai->Addr.SegmentKind.hasW = seg->hasW; |
| 302 | ai->Addr.SegmentKind.hasX = seg->hasX; |
| 303 | return; |
| 304 | } |
| 305 | } |
| 306 | |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 307 | /* -- Clueless ... -- */ |
| 308 | ai->tag = Addr_Unknown; |
| 309 | return; |
| 310 | } |
| 311 | |
philippe | 0c9ac8d | 2014-07-18 00:03:58 +0000 | [diff] [blame] | 312 | void VG_(initThreadInfo) (ThreadInfo *tinfo) |
| 313 | { |
| 314 | tinfo->tid = 0; |
| 315 | tinfo->tnr = 0; |
| 316 | } |
| 317 | |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 318 | void VG_(clear_addrinfo) ( AddrInfo* ai) |
| 319 | { |
| 320 | switch (ai->tag) { |
philippe | 0af05d4 | 2014-09-19 18:58:18 +0000 | [diff] [blame] | 321 | case Addr_Undescribed: |
| 322 | break; |
| 323 | |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 324 | case Addr_Unknown: |
philippe | 0af05d4 | 2014-09-19 18:58:18 +0000 | [diff] [blame] | 325 | break; |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 326 | |
| 327 | case Addr_Stack: |
philippe | 0af05d4 | 2014-09-19 18:58:18 +0000 | [diff] [blame] | 328 | break; |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 329 | |
| 330 | case Addr_Block: |
| 331 | break; |
| 332 | |
| 333 | case Addr_DataSym: |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 334 | VG_(free)(ai->Addr.DataSym.name); |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 335 | break; |
| 336 | |
| 337 | case Addr_Variable: |
| 338 | if (ai->Addr.Variable.descr1 != NULL) { |
| 339 | VG_(deleteXA)( ai->Addr.Variable.descr1 ); |
| 340 | ai->Addr.Variable.descr1 = NULL; |
| 341 | } |
| 342 | if (ai->Addr.Variable.descr2 != NULL) { |
| 343 | VG_(deleteXA)( ai->Addr.Variable.descr2 ); |
| 344 | ai->Addr.Variable.descr2 = NULL; |
| 345 | } |
| 346 | break; |
| 347 | |
| 348 | case Addr_SectKind: |
florian | e08950b | 2014-11-13 21:41:28 +0000 | [diff] [blame] | 349 | VG_(free)(ai->Addr.SectKind.objname); |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 350 | break; |
| 351 | |
philippe | d0da968 | 2014-12-28 17:30:22 +0000 | [diff] [blame] | 352 | case Addr_BrkSegment: |
| 353 | break; |
| 354 | |
philippe | f7ec77f | 2014-11-24 17:46:41 +0000 | [diff] [blame] | 355 | case Addr_SegmentKind: |
| 356 | VG_(free)(ai->Addr.SegmentKind.filename); |
| 357 | break; |
| 358 | |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 359 | default: |
| 360 | VG_(core_panic)("VG_(clear_addrinfo)"); |
| 361 | } |
| 362 | |
| 363 | ai->tag = Addr_Undescribed; |
| 364 | } |
| 365 | |
| 366 | static Bool is_arena_BlockKind(BlockKind bk) |
| 367 | { |
| 368 | switch (bk) { |
| 369 | case Block_Mallocd: |
| 370 | case Block_Freed: |
| 371 | case Block_MempoolChunk: |
| 372 | case Block_UserG: return False; |
| 373 | |
| 374 | case Block_ClientArenaMallocd: |
| 375 | case Block_ClientArenaFree: |
| 376 | case Block_ValgrindArenaMallocd: |
| 377 | case Block_ValgrindArenaFree: return True; |
| 378 | |
| 379 | default: vg_assert (0); |
| 380 | } |
| 381 | } |
| 382 | |
philippe | 0c9ac8d | 2014-07-18 00:03:58 +0000 | [diff] [blame] | 383 | static const HChar* opt_tnr_prefix (ThreadInfo tinfo) |
| 384 | { |
| 385 | if (tinfo.tnr != 0) |
| 386 | return "#"; |
| 387 | else |
| 388 | return ""; |
| 389 | } |
| 390 | |
| 391 | static UInt tnr_else_tid (ThreadInfo tinfo) |
| 392 | { |
| 393 | if (tinfo.tnr != 0) |
| 394 | return tinfo.tnr; |
| 395 | else |
| 396 | return tinfo.tid; |
| 397 | } |
| 398 | |
philippe | f7ec77f | 2014-11-24 17:46:41 +0000 | [diff] [blame] | 399 | static const HChar* pp_SegKind ( SegKind sk ) |
| 400 | { |
| 401 | switch (sk) { |
| 402 | case SkAnonC: return "anonymous"; |
| 403 | case SkFileC: return "mapped file"; |
| 404 | case SkShmC: return "shared memory"; |
| 405 | default: vg_assert(0); |
| 406 | } |
| 407 | } |
| 408 | |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 409 | static void pp_addrinfo_WRK ( Addr a, const AddrInfo* ai, Bool mc, |
| 410 | Bool maybe_gcc ) |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 411 | { |
| 412 | const HChar* xpre = VG_(clo_xml) ? " <auxwhat>" : " "; |
| 413 | const HChar* xpost = VG_(clo_xml) ? "</auxwhat>" : ""; |
| 414 | |
| 415 | vg_assert (!maybe_gcc || mc); // maybe_gcc can only be given in mc mode. |
| 416 | |
| 417 | switch (ai->tag) { |
philippe | 0af05d4 | 2014-09-19 18:58:18 +0000 | [diff] [blame] | 418 | case Addr_Undescribed: |
| 419 | VG_(core_panic)("mc_pp_AddrInfo Addr_Undescribed"); |
| 420 | |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 421 | case Addr_Unknown: |
| 422 | if (maybe_gcc) { |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 423 | VG_(emit)( "%sAddress 0x%lx is just below the stack ptr. " |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 424 | "To suppress, use: --workaround-gcc296-bugs=yes%s\n", |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 425 | xpre, a, xpost ); |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 426 | } else { |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 427 | VG_(emit)( "%sAddress 0x%lx " |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 428 | "is not stack'd, malloc'd or %s%s\n", |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 429 | xpre, a, |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 430 | mc ? "(recently) free'd" : "on a free list", |
| 431 | xpost ); |
| 432 | } |
| 433 | break; |
| 434 | |
| 435 | case Addr_Stack: |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 436 | VG_(emit)( "%sAddress 0x%lx is on thread %s%u's stack%s\n", |
| 437 | xpre, a, |
philippe | 0c9ac8d | 2014-07-18 00:03:58 +0000 | [diff] [blame] | 438 | opt_tnr_prefix (ai->Addr.Stack.tinfo), |
| 439 | tnr_else_tid (ai->Addr.Stack.tinfo), |
| 440 | xpost ); |
philippe | 18d6f4e | 2014-05-22 23:48:24 +0000 | [diff] [blame] | 441 | if (ai->Addr.Stack.frameNo != -1 && ai->Addr.Stack.IP != 0) { |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 442 | const HChar *fn; |
philippe | 18d6f4e | 2014-05-22 23:48:24 +0000 | [diff] [blame] | 443 | Bool hasfn; |
florian | 10ef725 | 2014-10-27 12:06:35 +0000 | [diff] [blame] | 444 | const HChar *file; |
philippe | 18d6f4e | 2014-05-22 23:48:24 +0000 | [diff] [blame] | 445 | Bool hasfile; |
| 446 | UInt linenum; |
| 447 | Bool haslinenum; |
| 448 | PtrdiffT offset; |
| 449 | |
philippe | 18d6f4e | 2014-05-22 23:48:24 +0000 | [diff] [blame] | 450 | if (VG_(get_inst_offset_in_function)( ai->Addr.Stack.IP, |
| 451 | &offset)) |
| 452 | haslinenum = VG_(get_linenum) (ai->Addr.Stack.IP - offset, |
| 453 | &linenum); |
| 454 | else |
| 455 | haslinenum = False; |
| 456 | |
florian | 10ef725 | 2014-10-27 12:06:35 +0000 | [diff] [blame] | 457 | hasfile = VG_(get_filename)(ai->Addr.Stack.IP, &file); |
| 458 | |
| 459 | HChar strlinenum[16] = ""; // large enough |
| 460 | if (hasfile && haslinenum) |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 461 | VG_(sprintf)(strlinenum, "%u", linenum); |
philippe | 18d6f4e | 2014-05-22 23:48:24 +0000 | [diff] [blame] | 462 | |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 463 | hasfn = VG_(get_fnname)(ai->Addr.Stack.IP, &fn); |
| 464 | |
philippe | 18d6f4e | 2014-05-22 23:48:24 +0000 | [diff] [blame] | 465 | if (hasfn || hasfile) |
Elliott Hughes | a0664b9 | 2017-04-18 17:46:52 -0700 | [diff] [blame] | 466 | VG_(emit)( "%sin frame #%d, created by %ps (%ps:%s)%s\n", |
philippe | 18d6f4e | 2014-05-22 23:48:24 +0000 | [diff] [blame] | 467 | xpre, |
| 468 | ai->Addr.Stack.frameNo, |
| 469 | hasfn ? fn : "???", |
florian | 10ef725 | 2014-10-27 12:06:35 +0000 | [diff] [blame] | 470 | hasfile ? file : "???", strlinenum, |
philippe | 18d6f4e | 2014-05-22 23:48:24 +0000 | [diff] [blame] | 471 | xpost ); |
philippe | 18d6f4e | 2014-05-22 23:48:24 +0000 | [diff] [blame] | 472 | } |
philippe | 7e3b3f2 | 2014-08-31 22:27:19 +0000 | [diff] [blame] | 473 | switch (ai->Addr.Stack.stackPos) { |
| 474 | case StackPos_stacked: break; // nothing more to say |
| 475 | |
| 476 | case StackPos_below_stack_ptr: |
| 477 | case StackPos_guard_page: |
| 478 | VG_(emit)("%s%s%ld bytes below stack pointer%s\n", |
| 479 | xpre, |
| 480 | ai->Addr.Stack.stackPos == StackPos_guard_page ? |
| 481 | "In stack guard protected page, " : "", |
| 482 | - ai->Addr.Stack.spoffset, |
| 483 | xpost); |
| 484 | // Note: we change the sign of spoffset as the message speaks |
| 485 | // about the nr of bytes below stack pointer. |
| 486 | break; |
| 487 | |
| 488 | default: vg_assert(0); |
| 489 | } |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 490 | break; |
| 491 | |
| 492 | case Addr_Block: { |
| 493 | SizeT block_szB = ai->Addr.Block.block_szB; |
| 494 | PtrdiffT rwoffset = ai->Addr.Block.rwoffset; |
| 495 | SizeT delta; |
| 496 | const HChar* relative; |
| 497 | |
| 498 | if (rwoffset < 0) { |
| 499 | delta = (SizeT)(-rwoffset); |
| 500 | relative = "before"; |
| 501 | } else if (rwoffset >= block_szB) { |
| 502 | delta = rwoffset - block_szB; |
| 503 | relative = "after"; |
| 504 | } else { |
| 505 | delta = rwoffset; |
| 506 | relative = "inside"; |
| 507 | } |
| 508 | if (is_arena_BlockKind (ai->Addr.Block.block_kind)) |
| 509 | VG_(emit)( |
| 510 | "%sAddress 0x%lx is %'lu bytes %s a%s block of size %'lu" |
| 511 | " in arena \"%s\"%s\n", |
| 512 | xpre, |
| 513 | a, delta, |
| 514 | relative, |
| 515 | ai->Addr.Block.block_kind==Block_ClientArenaMallocd |
| 516 | || ai->Addr.Block.block_kind==Block_ValgrindArenaMallocd |
| 517 | ? "" : "n unallocated", |
| 518 | block_szB, |
| 519 | ai->Addr.Block.block_desc, // arena name |
| 520 | xpost |
| 521 | ); |
| 522 | else |
| 523 | VG_(emit)( |
| 524 | "%sAddress 0x%lx is %'lu bytes %s a %s of size %'lu %s%s\n", |
| 525 | xpre, |
| 526 | a, delta, |
| 527 | relative, |
| 528 | ai->Addr.Block.block_desc, |
| 529 | block_szB, |
| 530 | ai->Addr.Block.block_kind==Block_Mallocd ? "alloc'd" |
| 531 | : ai->Addr.Block.block_kind==Block_Freed ? "free'd" |
| 532 | : "client-defined", |
| 533 | xpost |
| 534 | ); |
| 535 | if (ai->Addr.Block.block_kind==Block_Mallocd) { |
| 536 | VG_(pp_ExeContext)(ai->Addr.Block.allocated_at); |
florian | e2800c9 | 2014-09-15 20:57:45 +0000 | [diff] [blame] | 537 | vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)()); |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 538 | } |
| 539 | else if (ai->Addr.Block.block_kind==Block_Freed) { |
| 540 | VG_(pp_ExeContext)(ai->Addr.Block.freed_at); |
| 541 | if (ai->Addr.Block.allocated_at != VG_(null_ExeContext)()) { |
| 542 | VG_(emit)( |
philippe | 0c9ac8d | 2014-07-18 00:03:58 +0000 | [diff] [blame] | 543 | "%sBlock was alloc'd at%s\n", |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 544 | xpre, |
| 545 | xpost |
| 546 | ); |
| 547 | VG_(pp_ExeContext)(ai->Addr.Block.allocated_at); |
| 548 | } |
| 549 | } |
| 550 | else if (ai->Addr.Block.block_kind==Block_MempoolChunk |
| 551 | || ai->Addr.Block.block_kind==Block_UserG) { |
| 552 | // client-defined |
| 553 | VG_(pp_ExeContext)(ai->Addr.Block.allocated_at); |
florian | e2800c9 | 2014-09-15 20:57:45 +0000 | [diff] [blame] | 554 | vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)()); |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 555 | /* Nb: cannot have a freed_at, as a freed client-defined block |
| 556 | has a Block_Freed block_kind. */ |
| 557 | } else { |
| 558 | // Client or Valgrind arena. At least currently, we never |
| 559 | // have stacktraces for these. |
florian | e2800c9 | 2014-09-15 20:57:45 +0000 | [diff] [blame] | 560 | vg_assert (ai->Addr.Block.allocated_at == VG_(null_ExeContext)()); |
| 561 | vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)()); |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 562 | } |
philippe | 0c9ac8d | 2014-07-18 00:03:58 +0000 | [diff] [blame] | 563 | if (ai->Addr.Block.alloc_tinfo.tnr || ai->Addr.Block.alloc_tinfo.tid) |
| 564 | VG_(emit)( |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 565 | "%sBlock was alloc'd by thread %s%u%s\n", |
philippe | 0c9ac8d | 2014-07-18 00:03:58 +0000 | [diff] [blame] | 566 | xpre, |
| 567 | opt_tnr_prefix (ai->Addr.Block.alloc_tinfo), |
| 568 | tnr_else_tid (ai->Addr.Block.alloc_tinfo), |
| 569 | xpost |
| 570 | ); |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 571 | break; |
| 572 | } |
| 573 | |
| 574 | case Addr_DataSym: |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 575 | VG_(emit)( "%sAddress 0x%lx is %llu bytes " |
Elliott Hughes | a0664b9 | 2017-04-18 17:46:52 -0700 | [diff] [blame] | 576 | "inside data symbol \"%ps\"%s\n", |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 577 | xpre, a, |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 578 | (ULong)ai->Addr.DataSym.offset, |
| 579 | ai->Addr.DataSym.name, |
| 580 | xpost ); |
| 581 | break; |
| 582 | |
| 583 | case Addr_Variable: |
| 584 | /* Note, no need for XML tags here, because descr1/2 will |
| 585 | already have <auxwhat> or <xauxwhat>s on them, in XML |
| 586 | mode. */ |
| 587 | if (ai->Addr.Variable.descr1) |
| 588 | VG_(emit)( "%s%s\n", |
| 589 | VG_(clo_xml) ? " " : " ", |
| 590 | (HChar*)VG_(indexXA)(ai->Addr.Variable.descr1, 0) ); |
| 591 | if (ai->Addr.Variable.descr2) |
| 592 | VG_(emit)( "%s%s\n", |
| 593 | VG_(clo_xml) ? " " : " ", |
| 594 | (HChar*)VG_(indexXA)(ai->Addr.Variable.descr2, 0) ); |
| 595 | break; |
| 596 | |
| 597 | case Addr_SectKind: |
Elliott Hughes | a0664b9 | 2017-04-18 17:46:52 -0700 | [diff] [blame] | 598 | VG_(emit)( "%sAddress 0x%lx is in the %ps segment of %ps%s\n", |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 599 | xpre, a, |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 600 | VG_(pp_SectKind)(ai->Addr.SectKind.kind), |
| 601 | ai->Addr.SectKind.objname, |
| 602 | xpost ); |
philippe | a7cea05 | 2014-07-25 20:46:01 +0000 | [diff] [blame] | 603 | if (ai->Addr.SectKind.kind == Vg_SectText) { |
| 604 | /* To better describe the address in a text segment, |
| 605 | pp a dummy stacktrace made of this single address. */ |
| 606 | VG_(pp_StackTrace)( &a, 1 ); |
| 607 | } |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 608 | break; |
| 609 | |
philippe | d0da968 | 2014-12-28 17:30:22 +0000 | [diff] [blame] | 610 | case Addr_BrkSegment: |
| 611 | if (a < ai->Addr.BrkSegment.brk_limit) |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 612 | VG_(emit)( "%sAddress 0x%lx is in the brk data segment" |
| 613 | " 0x%lx-0x%lx%s\n", |
| 614 | xpre, a, |
| 615 | VG_(brk_base), |
| 616 | ai->Addr.BrkSegment.brk_limit - 1, |
philippe | d0da968 | 2014-12-28 17:30:22 +0000 | [diff] [blame] | 617 | xpost ); |
| 618 | else |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 619 | VG_(emit)( "%sAddress 0x%lx is %lu bytes after " |
philippe | d0da968 | 2014-12-28 17:30:22 +0000 | [diff] [blame] | 620 | "the brk data segment limit" |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 621 | " 0x%lx%s\n", |
| 622 | xpre, a, |
philippe | d0da968 | 2014-12-28 17:30:22 +0000 | [diff] [blame] | 623 | a - ai->Addr.BrkSegment.brk_limit, |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 624 | ai->Addr.BrkSegment.brk_limit, |
philippe | d0da968 | 2014-12-28 17:30:22 +0000 | [diff] [blame] | 625 | xpost ); |
| 626 | break; |
| 627 | |
philippe | f7ec77f | 2014-11-24 17:46:41 +0000 | [diff] [blame] | 628 | case Addr_SegmentKind: |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 629 | VG_(emit)( "%sAddress 0x%lx is in " |
Elliott Hughes | a0664b9 | 2017-04-18 17:46:52 -0700 | [diff] [blame] | 630 | "a %s%s%s %s%s%ps segment%s\n", |
philippe | f7ec77f | 2014-11-24 17:46:41 +0000 | [diff] [blame] | 631 | xpre, |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 632 | a, |
philippe | f7ec77f | 2014-11-24 17:46:41 +0000 | [diff] [blame] | 633 | ai->Addr.SegmentKind.hasR ? "r" : "-", |
| 634 | ai->Addr.SegmentKind.hasW ? "w" : "-", |
| 635 | ai->Addr.SegmentKind.hasX ? "x" : "-", |
| 636 | pp_SegKind(ai->Addr.SegmentKind.segkind), |
| 637 | ai->Addr.SegmentKind.filename ? |
| 638 | " " : "", |
| 639 | ai->Addr.SegmentKind.filename ? |
| 640 | ai->Addr.SegmentKind.filename : "", |
| 641 | xpost ); |
| 642 | break; |
| 643 | |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 644 | default: |
florian | a4ca4fe | 2014-09-16 09:28:12 +0000 | [diff] [blame] | 645 | VG_(core_panic)("mc_pp_AddrInfo"); |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 646 | } |
| 647 | } |
| 648 | |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 649 | void VG_(pp_addrinfo) ( Addr a, const AddrInfo* ai ) |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 650 | { |
| 651 | pp_addrinfo_WRK (a, ai, False /*mc*/, False /*maybe_gcc*/); |
| 652 | } |
| 653 | |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 654 | void VG_(pp_addrinfo_mc) ( Addr a, const AddrInfo* ai, Bool maybe_gcc ) |
philippe | 07c0852 | 2014-05-14 20:39:27 +0000 | [diff] [blame] | 655 | { |
| 656 | pp_addrinfo_WRK (a, ai, True /*mc*/, maybe_gcc); |
| 657 | } |
| 658 | |
| 659 | |
| 660 | /*--------------------------------------------------------------------*/ |
| 661 | /*--- end m_addrinfo.c ---*/ |
| 662 | /*--------------------------------------------------------------------*/ |