1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Top level management of symbols and debugging information.   ---*/
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                  debuginfo.c ---*/
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This file is part of Valgrind, a dynamic binary instrumentation
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   framework.
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Copyright (C) 2000-2013 Julian Seward
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jseward@acm.org
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is free software; you can redistribute it and/or
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modify it under the terms of the GNU General Public License as
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   published by the Free Software Foundation; either version 2 of the
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   License, or (at your option) any later version.
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is distributed in the hope that it will be useful, but
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WITHOUT ANY WARRANTY; without even the implied warranty of
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   General Public License for more details.
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   You should have received a copy of the GNU General Public License
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   along with this program; if not, write to the Free Software
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   02111-1307, USA.
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The GNU General Public License is contained in the file COPYING.
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_basics.h"
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_vki.h"
34b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_threadstate.h"
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_debuginfo.h"  /* self */
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_demangle.h"
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcbase.h"
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcassert.h"
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcprint.h"
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcfile.h"
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcproc.h"   // VG_(getenv)
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_seqmatch.h"
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_options.h"
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_redir.h"      // VG_(redir_notify_{new,delete}_SegInfo)
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_aspacemgr.h"
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_machine.h"    // VG_PLAT_USES_PPCTOC
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_xarray.h"
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_oset.h"
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_stacktrace.h" // VG_(get_StackTrace) XXX: circular dependency
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_ume.h"
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "priv_misc.h"           /* dinfo_zalloc/free */
54436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "priv_image.h"
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "priv_d3basics.h"       /* ML_(pp_GX) */
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "priv_tytypes.h"
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "priv_storage.h"
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "priv_readdwarf.h"
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "priv_readstabs.h"
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_linux)
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# include "priv_readelf.h"
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# include "priv_readdwarf3.h"
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# include "priv_readpdb.h"
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGO_darwin)
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# include "priv_readmacho.h"
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# include "priv_readpdb.h"
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- The _svma / _avma / _image / _bias naming scheme     ---*/
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* JRS 11 Jan 07: I find the different kinds of addresses involved in
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   debuginfo reading confusing.  Recently I arrived at some
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   terminology which makes it clearer (to me, at least).  There are 3
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   kinds of address used in the debuginfo reading process:
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stated VMAs - the address where (eg) a .so says a symbol is, that
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 is, what it tells you if you consider the .so in
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 isolation
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   actual VMAs - the address where (eg) said symbol really wound up
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 after the .so was mapped into memory
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   image addresses - pointers into the copy of the .so (etc)
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     transiently mmaped aboard whilst we read its info
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Additionally I use the term 'bias' to denote the difference
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   between stated and actual VMAs for a given entity.
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This terminology is not used consistently, but a start has been
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   made.  readelf.c and the call-frame info reader in readdwarf.c now
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   use it.  Specifically, various variables and structure fields have
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   been annotated with _avma / _svma / _image / _bias.  In places _img
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is used instead of _image for the sake of brevity.
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- fwdses                                               ---*/
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
104436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic UInt CF_info_generation = 0;
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void cfsi_cache__invalidate ( void );
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Root structure                                       ---*/
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The root structure for the entire debug info system.  It is a
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   linked list of DebugInfos. */
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic DebugInfo* debugInfo_list = NULL;
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Find 'di' in the debugInfo_list and move it one step closer the the
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   front of the list, so as to make subsequent searches for it
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cheaper.  When used in a controlled way, makes a major improvement
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in some DebugInfo-search-intensive situations, most notably stack
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unwinding on amd64-linux. */
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void move_DebugInfo_one_step_forward ( DebugInfo* di )
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo *di0, *di1, *di2;
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (di == debugInfo_list)
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return; /* already at head of list */
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(di != NULL);
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   di0 = debugInfo_list;
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   di1 = NULL;
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   di2 = NULL;
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (True) {
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di0 == NULL || di0 == di) break;
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di2 = di1;
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di1 = di0;
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di0 = di0->next;
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(di0 == di);
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (di0 != NULL && di1 != NULL && di2 != NULL) {
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DebugInfo* tmp;
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* di0 points to di, di1 to its predecessor, and di2 to di1's
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         predecessor.  Swap di0 and di1, that is, move di0 one step
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         closer to the start of the list. */
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(di2->next == di1);
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(di1->next == di0);
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmp = di0->next;
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di2->next = di0;
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di0->next = di1;
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di1->next = tmp;
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (di0 != NULL && di1 != NULL && di2 == NULL) {
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* it's second in the list. */
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(debugInfo_list == di1);
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(di1->next == di0);
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di1->next = di0->next;
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di0->next = di1;
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      debugInfo_list = di0;
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Notification (acquire/discard) helpers               ---*/
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Gives out unique abstract handles for allocated DebugInfos.  See
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   comment in priv_storage.h, declaration of struct _DebugInfo, for
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   details. */
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong handle_counter = 1;
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Allocate and zero out a new DebugInfo record. */
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
173436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovDebugInfo* alloc_DebugInfo( const HChar* filename )
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool       traceme;
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* di;
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(filename);
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   di = ML_(dinfo_zalloc)("di.debuginfo.aDI.1", sizeof(DebugInfo));
181b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   di->handle       = handle_counter++;
182b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   di->fsm.filename = ML_(dinfo_strdup)("di.debuginfo.aDI.2", filename);
183663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   di->fsm.maps     = VG_(newXA)(
184663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                         ML_(dinfo_zalloc), "di.debuginfo.aDI.3",
185663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                         ML_(dinfo_free), sizeof(struct _DebugInfoMapping));
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
187b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Everything else -- pointers, sizes, arrays -- is zeroed by
188b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      ML_(dinfo_zalloc).  Now set up the debugging-output flags. */
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   traceme
190b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      = VG_(string_match)( VG_(clo_trace_symtab_patt), filename );
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (traceme) {
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di->trace_symtab = VG_(clo_trace_symtab);
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di->trace_cfi    = VG_(clo_trace_cfi);
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di->ddump_syms   = VG_(clo_debug_dump_syms);
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di->ddump_line   = VG_(clo_debug_dump_line);
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di->ddump_frames = VG_(clo_debug_dump_frames);
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return di;
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Free a DebugInfo, and also all the stuff hanging off it. */
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void free_DebugInfo ( DebugInfo* di )
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word i, j, n;
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct strchunk *chunk, *next;
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TyEnt* ent;
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   GExpr* gexpr;
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(di != NULL);
212663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if (di->fsm.maps)     VG_(deleteXA)(di->fsm.maps);
213b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (di->fsm.filename) ML_(dinfo_free)(di->fsm.filename);
214663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if (di->soname)       ML_(dinfo_free)(di->soname);
215b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (di->loctab)       ML_(dinfo_free)(di->loctab);
216b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (di->cfsi)         ML_(dinfo_free)(di->cfsi);
217b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (di->cfsi_exprs)   VG_(deleteXA)(di->cfsi_exprs);
218b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (di->fpo)          ML_(dinfo_free)(di->fpo);
219b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
220b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (di->symtab) {
221b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* We have to visit all the entries so as to free up any
222b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         sec_names arrays that might exist. */
223b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      n = di->symtab_used;
224b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      for (i = 0; i < n; i++) {
225b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         DiSym* sym = &di->symtab[i];
226b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (sym->sec_names)
227b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            ML_(dinfo_free)(sym->sec_names);
228b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
229b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* and finally .. */
230b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      ML_(dinfo_free)(di->symtab);
231b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (chunk = di->strchunks; chunk != NULL; chunk = next) {
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      next = chunk->next;
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ML_(dinfo_free)(chunk);
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Delete the two admin arrays.  These lists exist primarily so
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      that we can visit each object exactly once when we need to
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delete them. */
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (di->admin_tyents) {
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n = VG_(sizeXA)(di->admin_tyents);
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < n; i++) {
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ent = (TyEnt*)VG_(indexXA)(di->admin_tyents, i);
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Dump anything hanging off this ent */
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ML_(TyEnt__make_EMPTY)(ent);
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(deleteXA)(di->admin_tyents);
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di->admin_tyents = NULL;
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (di->admin_gexprs) {
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n = VG_(sizeXA)(di->admin_gexprs);
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < n; i++) {
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gexpr = *(GExpr**)VG_(indexXA)(di->admin_gexprs, i);
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ML_(dinfo_free)(gexpr);
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(deleteXA)(di->admin_gexprs);
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di->admin_gexprs = NULL;
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Dump the variable info.  This is kinda complex: we must take
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      care not to free items which reside in either the admin lists
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (as we have just freed them) or which reside in the DebugInfo's
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      string table. */
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (di->varinfo) {
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < VG_(sizeXA)(di->varinfo); i++) {
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         OSet* scope = *(OSet**)VG_(indexXA)(di->varinfo, i);
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!scope) continue;
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* iterate over all entries in 'scope' */
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(OSetGen_ResetIter)(scope);
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         while (True) {
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DiAddrRange* arange = VG_(OSetGen_Next)(scope);
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!arange) break;
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* for each var in 'arange' */
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vg_assert(arange->vars);
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for (j = 0; j < VG_(sizeXA)( arange->vars ); j++) {
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DiVariable* var = (DiVariable*)VG_(indexXA)(arange->vars,j);
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vg_assert(var);
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Nothing to free in var: all the pointer fields refer
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  to stuff either on an admin list, or in
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  .strchunks */
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(deleteXA)(arange->vars);
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Don't free arange itself, as OSetGen_Destroy does
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               that */
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(OSetGen_Destroy)(scope);
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(deleteXA)(di->varinfo);
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ML_(dinfo_free)(di);
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* 'si' is a member of debugInfo_list.  Find it, remove it from the
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   list, notify m_redir that this has happened, and free all storage
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   reachable from it.
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void discard_DebugInfo ( DebugInfo* di )
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
303436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   const HChar* reason = "munmap";
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo** prev_next_ptr = &debugInfo_list;
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo*  curr          =  debugInfo_list;
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (curr) {
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (curr == di) {
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Found it;  remove from list and free it. */
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (curr->have_dinfo
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && (VG_(clo_verbosity) > 1 || VG_(clo_trace_redir)))
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(message)(Vg_DebugMsg,
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         "Discarding syms at %#lx-%#lx in %s due to %s()\n",
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         di->text_avma,
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         di->text_avma + di->text_size,
317b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                         curr->fsm.filename ? curr->fsm.filename
318436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                            : "???",
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         reason);
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(*prev_next_ptr == curr);
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *prev_next_ptr = curr->next;
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (curr->have_dinfo)
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(redir_notify_delete_DebugInfo)( curr );
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         free_DebugInfo(curr);
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return;
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      prev_next_ptr = &curr->next;
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      curr          =  curr->next;
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Not found. */
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Repeatedly scan debugInfo_list, looking for DebugInfos with text
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AVMAs intersecting [start,start+length), and call discard_DebugInfo
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to get rid of them.  This modifies the list, hence the multiple
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   iterations.  Returns True iff any such DebugInfos were found.
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool discard_syms_in_range ( Addr start, SizeT length )
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool       anyFound = False;
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool       found;
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* curr;
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (True) {
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      found = False;
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      curr = debugInfo_list;
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      while (True) {
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (curr == NULL)
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (curr->text_present
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && curr->text_size > 0
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && (start+length - 1 < curr->text_avma
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 || curr->text_avma + curr->text_size - 1 < start)) {
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* no overlap */
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 } else {
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    found = True;
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    break;
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 }
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 curr = curr->next;
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!found) break;
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      anyFound = True;
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      discard_DebugInfo( curr );
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return anyFound;
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Does [s1,+len1) overlap [s2,+len2) ?  Note: does not handle
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   wraparound at the end of the address space -- just asserts in that
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case. */
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool ranges_overlap (Addr s1, SizeT len1, Addr s2, SizeT len2 )
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr e1, e2;
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (len1 == 0 || len2 == 0)
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   e1 = s1 + len1 - 1;
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   e2 = s2 + len2 - 1;
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Assert that we don't have wraparound.  If we do it would imply
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      that file sections are getting mapped around the end of the
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      address space, which sounds unlikely. */
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(s1 <= e1);
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(s2 <= e2);
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (e1 < s2 || e2 < s1) return False;
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
394663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng/* Do the basic mappings of the two DebugInfos overlap in any way? */
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool do_DebugInfos_overlap ( DebugInfo* di1, DebugInfo* di2 )
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
397663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Word i, j;
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(di1);
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(di2);
400663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   for (i = 0; i < VG_(sizeXA)(di1->fsm.maps); i++) {
401663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      struct _DebugInfoMapping* map1 = VG_(indexXA)(di1->fsm.maps, i);
402663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      for (j = 0; j < VG_(sizeXA)(di2->fsm.maps); j++) {
403663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         struct _DebugInfoMapping* map2 = VG_(indexXA)(di2->fsm.maps, j);
404663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         if (ranges_overlap(map1->avma, map1->size, map2->avma, map2->size))
405663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            return True;
406663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      }
407663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Discard all elements of debugInfo_list whose .mark bit is set.
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void discard_marked_DebugInfos ( void )
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* curr;
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (True) {
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      curr = debugInfo_list;
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      while (True) {
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!curr)
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (curr->mark)
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 curr = curr->next;
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!curr) break;
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      discard_DebugInfo( curr );
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Discard any elements of debugInfo_list which overlap with diRef.
438663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Clearly diRef must have its mapping information set to something sane. */
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void discard_DebugInfos_which_overlap_with ( DebugInfo* diRef )
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* di;
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Mark all the DebugInfos in debugInfo_list that need to be
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      deleted.  First, clear all the mark bits; then set them if they
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      overlap with siRef.  Since siRef itself is in this list we at
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      least expect its own mark bit to be set. */
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (di = debugInfo_list; di; di = di->next) {
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di->mark = do_DebugInfos_overlap( di, diRef );
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di == diRef) {
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(di->mark);
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         di->mark = False;
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   discard_marked_DebugInfos();
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
457b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Find the existing DebugInfo for |filename| or if not found, create
458b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   one.  In the latter case |filename| is strdup'd into VG_AR_DINFO,
459b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   and the new DebugInfo is added to debugInfo_list. */
460436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic DebugInfo* find_or_create_DebugInfo_for ( HChar* filename )
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* di;
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(filename);
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (di = debugInfo_list; di; di = di->next) {
465b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      vg_assert(di->fsm.filename);
466b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (0==VG_(strcmp)(di->fsm.filename, filename))
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!di) {
470b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      di = alloc_DebugInfo(filename);
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(di);
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di->next = debugInfo_list;
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      debugInfo_list = di;
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return di;
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Debuginfo reading for 'di' has just been successfully completed.
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Check that the invariants stated in
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   "Comment_on_IMPORTANT_CFSI_REPRESENTATIONAL_INVARIANTS" in
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   priv_storage.h are observed. */
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void check_CFSI_related_invariants ( DebugInfo* di )
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* di2 = NULL;
486663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Bool has_nonempty_rx = False;
487663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Bool cfsi_fits = False;
488663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Word i, j;
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(di);
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This fn isn't called until after debuginfo for this object has
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      been successfully read.  And that shouldn't happen until we have
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      both a r-x and rw- mapping for the object.  Hence: */
493b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(di->fsm.have_rx_map);
494b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(di->fsm.have_rw_map);
495663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) {
496663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      struct _DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i);
497663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      /* We are interested in r-x mappings only */
498663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      if (!map->rx)
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
500663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
501663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      /* degenerate case: r-x section is empty */
502663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      if (map->size == 0)
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
504663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      has_nonempty_rx = True;
505663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
506663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      /* normal case: r-x section is nonempty */
507663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      /* invariant (0) */
508663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vg_assert(map->size > 0);
509663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
510663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      /* invariant (1) */
511663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      for (di2 = debugInfo_list; di2; di2 = di2->next) {
512663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         if (di2 == di)
513663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            continue;
514663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         for (j = 0; j < VG_(sizeXA)(di2->fsm.maps); j++) {
515663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            struct _DebugInfoMapping* map2 = VG_(indexXA)(di2->fsm.maps, j);
516663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            if (!map2->rx || map2->size == 0)
517663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               continue;
518663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            vg_assert(!ranges_overlap(map->avma,  map->size,
519663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                      map2->avma, map2->size));
520663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         }
521663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      }
522663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      di2 = NULL;
523663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
524663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      /* invariant (2) */
525663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      if (di->cfsi) {
526663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         vg_assert(di->cfsi_minavma <= di->cfsi_maxavma); /* duh! */
527663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         /* Assume the csfi fits completely into one individual mapping
528663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            for now. This might need to be improved/reworked later. */
529663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         if (di->cfsi_minavma >= map->avma &&
530663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng             di->cfsi_maxavma <  map->avma + map->size)
531663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            cfsi_fits = True;
532663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      }
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
534663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
535663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* degenerate case: all r-x sections are empty */
536663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if (!has_nonempty_rx) {
537663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vg_assert(di->cfsi == NULL);
538663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      return;
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
540663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
541663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* invariant (2) - cont. */
542663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if (di->cfsi)
543663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vg_assert(cfsi_fits);
544663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* invariants (3) and (4) */
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (di->cfsi) {
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(di->cfsi_used > 0);
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(di->cfsi_size > 0);
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < di->cfsi_used; i++) {
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DiCfSI* cfsi = &di->cfsi[i];
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(cfsi->len > 0);
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(cfsi->base >= di->cfsi_minavma);
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(cfsi->base + cfsi->len - 1 <= di->cfsi_maxavma);
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (i > 0) {
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DiCfSI* cfsip = &di->cfsi[i-1];
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vg_assert(cfsip->base + cfsip->len <= cfsi->base);
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(di->cfsi_used == 0);
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(di->cfsi_size == 0);
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------*/
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                        ---*/
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- TOP LEVEL: INITIALISE THE DEBUGINFO SYSTEM             ---*/
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                        ---*/
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------*/
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(di_initialise) ( void )
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* There's actually very little to do here, since everything
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      centers around the DebugInfos in debugInfo_list, they are
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      created and destroyed on demand, and each one is treated more or
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      less independently. */
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(debugInfo_list == NULL);
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* flush the CFI fast query cache. */
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cfsi_cache__invalidate();
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------*/
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                        ---*/
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- TOP LEVEL: NOTIFICATION (ACQUIRE/DISCARD INFO) (LINUX) ---*/
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                        ---*/
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------*/
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_linux)  ||  defined(VGO_darwin)
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The debug info system is driven by notifications that a text
594b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   segment has been mapped in, or unmapped, or when sections change
595b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   permission.  It's all a bit kludgey and basically means watching
596b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   syscalls, trying to second-guess when the system's dynamic linker
597b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   is done with mapping in a new object for execution.  This is all
598b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tracked using the DebugInfoFSM struct for the object.  Anyway, once
599b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   we finally decide we've got to an accept state, this section then
600b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   will acquire whatever info is available for the corresponding
601b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   object.  This section contains the notification handlers, which
602b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   update the FSM and determine when an accept state has been reached.
603b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov*/
6048f943afc22a6a683b78271836c8ddc462b4824a9Evgeniy Stepanov
605b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* When the sequence of observations causes a DebugInfoFSM to move
606b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   into the accept state, call here to actually get the debuginfo read
607b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   in.  Returns a ULong whose purpose is described in comments
608b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   preceding VG_(di_notify_mmap) just below.
609b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov*/
610b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic ULong di_notify_ACHIEVE_ACCEPT_STATE ( struct _DebugInfo* di )
611b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
612b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   ULong di_handle;
613b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Bool  ok;
6148f943afc22a6a683b78271836c8ddc462b4824a9Evgeniy Stepanov
615b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(di->fsm.filename);
616b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   TRACE_SYMTAB("\n");
617b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   TRACE_SYMTAB("------ start ELF OBJECT "
618b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                "------------------------------\n");
619b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   TRACE_SYMTAB("------ name = %s\n", di->fsm.filename);
620b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   TRACE_SYMTAB("\n");
621b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
622b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* We're going to read symbols and debug info for the avma
623663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      ranges specified in the _DebugInfoFsm mapping array. First
624663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      get rid of any other DebugInfos which overlap any of those
625663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      ranges (to avoid total confusion). */
626b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   discard_DebugInfos_which_overlap_with( di );
627b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
628b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* .. and acquire new info. */
629b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux)
630b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   ok = ML_(read_elf_debug_info)( di );
631b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  elif defined(VGO_darwin)
632b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   ok = ML_(read_macho_debug_info)( di );
633b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  else
634b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#    error "unknown OS"
635b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  endif
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
637b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (ok) {
638f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov
639f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      TRACE_SYMTAB("\n------ Canonicalising the "
640f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov                   "acquired info ------\n");
641f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      /* invalidate the CFI unwind cache. */
642f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      cfsi_cache__invalidate();
643f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      /* prepare read data for use */
644f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      ML_(canonicaliseTables)( di );
645f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      /* notify m_redir about it */
646f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      TRACE_SYMTAB("\n------ Notifying m_redir ------\n");
647f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      VG_(redir_notify_new_DebugInfo)( di );
648f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      /* Note that we succeeded */
649f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      di->have_dinfo = True;
650b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert(di->handle > 0);
651b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      di_handle = di->handle;
652f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      /* Check invariants listed in
653f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov         Comment_on_IMPORTANT_REPRESENTATIONAL_INVARIANTS in
654f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov         priv_storage.h. */
655f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      check_CFSI_related_invariants(di);
656b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
657b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else {
658b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      TRACE_SYMTAB("\n------ ELF reading failed ------\n");
659b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* Something went wrong (eg. bad ELF file).  Should we delete
660b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         this DebugInfo?  No - it contains info on the rw/rx
661b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         mappings, at least. */
662b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      di_handle = 0;
663b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      vg_assert(di->have_dinfo == False);
664b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
665b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
666b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   TRACE_SYMTAB("\n");
667b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   TRACE_SYMTAB("------ name = %s\n", di->fsm.filename);
668b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   TRACE_SYMTAB("------ end ELF OBJECT "
669b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                "------------------------------\n");
670b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   TRACE_SYMTAB("\n");
671b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
672b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return di_handle;
673f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov}
674f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov
675b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
676b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Notify the debuginfo system about a new mapping.  This is the way
677b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   new debug information gets loaded.  If allow_SkFileV is True, it
678b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   will try load debug info if the mapping at 'a' belongs to Valgrind;
679b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   whereas normally (False) it will not do that.  This allows us to
680b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   carefully control when the thing will read symbols from the
681b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Valgrind executable itself.
682b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
683b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   If use_fd is not -1, that is used instead of the filename; this
684b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   avoids perturbing fcntl locks, which are released by simply
685b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   re-opening and closing the same file (even via different fd!).
686b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
687b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   If a call to VG_(di_notify_mmap) causes debug info to be read, then
688b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   the returned ULong is an abstract handle which can later be used to
689b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   refer to the debuginfo read as a result of this specific mapping,
690b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   in later queries to m_debuginfo.  In this case the handle value
691b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   will be one or above.  If the returned value is zero, no debug info
692b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   was read. */
693b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
694b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd )
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NSegment const * seg;
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar*     filename;
698b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Bool       is_rx_map, is_rw_map, is_ro_map;
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* di;
700b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Int        actual_fd, oflags;
701b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   SysRes     preadres;
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar      buf1k[1024];
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool       debug = False;
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes     statres;
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vg_stat statbuf;
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
707b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(use_fd >= -1);
708b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* In short, figure out if this mapping is of interest to us, and
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if so, try to guess what ld.so is doing and when/if we should
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      read debug info. */
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   seg = VG_(am_find_nsegment)(a);
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(seg);
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (debug)
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("di_notify_mmap-1: %#lx-%#lx %c%c%c\n",
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  seg->start, seg->end,
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  seg->hasR ? 'r' : '-',
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  seg->hasW ? 'w' : '-',seg->hasX ? 'x' : '-' );
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* guaranteed by aspacemgr-linux.c, sane_NSegment() */
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(seg->end > seg->start);
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Ignore non-file mappings */
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( ! (seg->kind == SkFileC
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || (seg->kind == SkFileV && allow_SkFileV)) )
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 0;
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If the file doesn't have a name, we're hosed.  Give up. */
730436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   filename = VG_(am_get_filename)( seg );
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!filename)
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 0;
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
734436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /*
735436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    * Cannot read from these magic files:
736436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    * --20208-- WARNING: Serious error when reading debug info
737436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    * --20208-- When reading debug info from /proc/xen/privcmd:
738436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    * --20208-- can't read file to inspect ELF header
739436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    */
740436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (VG_(strncmp)(filename, "/proc/xen/", 10) == 0)
741436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return 0;
742436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (debug)
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("di_notify_mmap-2: %s\n", filename);
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Only try to read debug information from regular files.  */
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   statres = VG_(stat)(filename, &statbuf);
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* stat dereferences symlinks, so we don't expect it to succeed and
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      yet produce something that is a symlink. */
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sr_isError(statres) || ! VKI_S_ISLNK(statbuf.mode));
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Don't let the stat call fail silently.  Filter out some known
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sources of noise before complaining, though. */
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(statres)) {
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DebugInfo fake_di;
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool quiet = VG_(strstr)(filename, "/var/run/nscd/") != NULL;
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!quiet && VG_(clo_verbosity) > 1) {
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(memset)(&fake_di, 0, sizeof(fake_di));
760b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         fake_di.fsm.filename = filename;
761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ML_(symerr)(&fake_di, True, "failed to stat64/stat this file");
762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 0;
764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Finally, the point of all this stattery: if it's not a regular file,
767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      don't try to read debug info from it. */
768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (! VKI_S_ISREG(statbuf.mode))
769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 0;
770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* no uses of statbuf below here. */
772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Now we have to guess if this is a text-like mapping, a data-like
774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mapping, neither or both.  The rules are:
775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        text if:   x86-linux    r and x
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   other-linux  r and x and not w
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        data if:   x86-linux    r and w
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   other-linux  r and w and not x
781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Background: On x86-linux, objects are typically mapped twice:
783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      1b8fb000-1b8ff000 r-xp 00000000 08:02 4471477 vgpreload_memcheck.so
785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      1b8ff000-1b900000 rw-p 00004000 08:02 4471477 vgpreload_memcheck.so
786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      whereas ppc32-linux mysteriously does this:
788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      118a6000-118ad000 r-xp 00000000 08:05 14209428 vgpreload_memcheck.so
790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      118ad000-118b6000 ---p 00007000 08:05 14209428 vgpreload_memcheck.so
791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      118b6000-118bd000 rwxp 00000000 08:05 14209428 vgpreload_memcheck.so
792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      The third mapping should not be considered to have executable
794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      code in.  Therefore a test which works for both is: r and x and
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      NOT w.  Reading symbols from the rwx segment -- which overlaps
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the r-x segment in the file -- causes the redirection mechanism
797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to redirect to addresses in that third segment, which is wrong
798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      and causes crashes.
799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      JRS 28 Dec 05: unfortunately icc 8.1 on x86 has been seen to
801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      produce executables with a single rwx segment rather than a
802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (r-x,rw-) pair. That means the rules have to be modified thusly:
803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      x86-linux:   consider if r and x
805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all others:  consider if r and x and not w
806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      2009 Aug 16: apply similar kludge to ppc32-linux.
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      See http://bugs.kde.org/show_bug.cgi?id=190820
809b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
810b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      There are two modes on s390x: with and without the noexec kernel
811b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      parameter. Together with some older kernels, this leads to several
812b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      variants:
813b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      executable: r and x
814b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      data:       r and w and x
815b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      or
816b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      executable: r and x
817b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      data:       r and w
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is_rx_map = False;
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is_rw_map = False;
821b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   is_ro_map = False;
822b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
823436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  if defined(VGA_x86) || defined(VGA_ppc32) || defined(VGA_mips32) \
824436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      || defined(VGA_mips64)
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is_rx_map = seg->hasR && seg->hasX;
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is_rw_map = seg->hasR && seg->hasW;
827436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  elif defined(VGA_amd64) || defined(VGA_ppc64) || defined(VGA_arm) \
828436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        || defined(VGA_arm64)
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is_rx_map = seg->hasR && seg->hasX && !seg->hasW;
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is_rw_map = seg->hasR && seg->hasW && !seg->hasX;
831b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  elif defined(VGP_s390x_linux)
832b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   is_rx_map = seg->hasR && seg->hasX && !seg->hasW;
833b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   is_rw_map = seg->hasR && seg->hasW;
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown platform"
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
838b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGP_x86_darwin) && DARWIN_VERS == DARWIN_10_7
839b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   is_ro_map = seg->hasR && !seg->hasW && !seg->hasX;
840b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  endif
841b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (debug)
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("di_notify_mmap-3: is_rx_map %d, is_rw_map %d\n",
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (Int)is_rx_map, (Int)is_rw_map);
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
846b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Ignore mappings with permissions we can't possibly be interested in. */
847b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (!(is_rx_map || is_rw_map || is_ro_map))
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 0;
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Peer at the first few bytes of the file, to see if it is an ELF */
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* object file. Ignore the file if we do not have read permission. */
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(buf1k, 0, sizeof(buf1k));
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   oflags = VKI_O_RDONLY;
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VKI_O_LARGEFILE)
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   oflags |= VKI_O_LARGEFILE;
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
857b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
858b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (use_fd == -1) {
859b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      SysRes fd = VG_(open)( filename, oflags, 0 );
860b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (sr_isError(fd)) {
861b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (sr_Err(fd) != VKI_EACCES) {
862b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            DebugInfo fake_di;
863b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(memset)(&fake_di, 0, sizeof(fake_di));
864b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            fake_di.fsm.filename = filename;
865b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            ML_(symerr)(&fake_di, True,
866b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                        "can't open file to inspect ELF header");
867b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
868b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         return 0;
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
870b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      actual_fd = sr_Res(fd);
871b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else {
872b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      actual_fd = use_fd;
8738f943afc22a6a683b78271836c8ddc462b4824a9Evgeniy Stepanov   }
8748f943afc22a6a683b78271836c8ddc462b4824a9Evgeniy Stepanov
875b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   preadres = VG_(pread)( actual_fd, buf1k, sizeof(buf1k), 0 );
876b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (use_fd == -1) {
877b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(close)( actual_fd );
878b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
879b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
880b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (sr_isError(preadres)) {
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DebugInfo fake_di;
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(memset)(&fake_di, 0, sizeof(fake_di));
883b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      fake_di.fsm.filename = filename;
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ML_(symerr)(&fake_di, True, "can't read file to inspect ELF header");
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 0;
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
887b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (sr_Res(preadres) == 0)
888b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return 0;
889b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(sr_Res(preadres) > 0 && sr_Res(preadres) <= sizeof(buf1k) );
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We're only interested in mappings of object files. */
892b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux)
893663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if (!ML_(is_elf_object_file)( buf1k, (SizeT)sr_Res(preadres), False ))
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 0;
895b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  elif defined(VGO_darwin)
896b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (!ML_(is_macho_object_file)( buf1k, (SizeT)sr_Res(preadres) ))
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 0;
898b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  else
899b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#    error "unknown OS"
900b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  endif
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* See if we have a DebugInfo for this filename.  If not,
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      create one. */
904b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   di = find_or_create_DebugInfo_for( filename );
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(di);
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
907663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* Note the details about the mapping. */
908663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   struct _DebugInfoMapping map;
909663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   map.avma = a;
910663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   map.size = seg->end + 1 - seg->start;
911663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   map.foff = seg->offset;
912663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   map.rx   = is_rx_map;
913663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   map.rw   = is_rw_map;
914663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   map.ro   = is_ro_map;
915663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(addToXA)(di->fsm.maps, &map);
916663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
917663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* Update flags about what kind of mappings we've already seen. */
918663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   di->fsm.have_rx_map |= is_rx_map;
919663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   di->fsm.have_rw_map |= is_rw_map;
920663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   di->fsm.have_ro_map |= is_ro_map;
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
922b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* So, finally, are we in an accept state? */
923b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (di->fsm.have_rx_map && di->fsm.have_rw_map && !di->have_dinfo) {
924b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* Ok, so, finally, we found what we need, and we haven't
925b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         already read debuginfo for this object.  So let's do so now.
926b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         Yee-ha! */
927b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return di_notify_ACHIEVE_ACCEPT_STATE ( di );
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
929b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* If we don't have an rx and rw mapping, or if we already have
930b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         debuginfo for this mapping for whatever reason, go no
931b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         further. */
932b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return 0;
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Unmap is simpler - throw away any SegInfos intersecting
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   [a, a+len).  */
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(di_notify_munmap)( Addr a, SizeT len )
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool anyFound;
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) VG_(printf)("DISCARD %#lx %#lx\n", a, a+len);
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   anyFound = discard_syms_in_range(a, len);
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (anyFound)
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cfsi_cache__invalidate();
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Uh, this doesn't do anything at all.  IIRC glibc (or ld.so, I don't
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   remember) does a bunch of mprotects on itself, and if we follow
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   through here, it causes the debug info for that object to get
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   discarded. */
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(di_notify_mprotect)( Addr a, SizeT len, UInt prot )
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool exe_ok = toBool(prot & VKI_PROT_EXEC);
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGA_x86)
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   exe_ok = exe_ok || toBool(prot & VKI_PROT_READ);
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 && !exe_ok) {
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool anyFound = discard_syms_in_range(a, len);
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (anyFound)
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         cfsi_cache__invalidate();
963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
966b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
967b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* This is a MacOSX 10.7 32-bit only special.  See comments on the
968b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   declaration of struct _DebugInfoFSM for details. */
969b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid VG_(di_notify_vm_protect)( Addr a, SizeT len, UInt prot )
970b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
971b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Bool do_nothing = True;
972663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  if defined(VGP_x86_darwin) && (DARWIN_VERS == DARWIN_10_7 || DARWIN_VERS == DARWIN_10_8)
973b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   do_nothing = False;
974b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  endif
975b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (do_nothing /* wrong platform */)
976b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return;
977b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
978b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Bool r_ok = toBool(prot & VKI_PROT_READ);
979b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Bool w_ok = toBool(prot & VKI_PROT_WRITE);
980b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Bool x_ok = toBool(prot & VKI_PROT_EXEC);
981b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (! (r_ok && !w_ok && x_ok))
982b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return; /* not an upgrade to r-x */
983b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
984b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Find a DebugInfo containing a FSM that has [a, +len) previously
985b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      observed as a r-- mapping, plus some other rw- mapping.  If such
986b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      is found, conclude we're in an accept state and read debuginfo
987b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      accordingly. */
988b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   DebugInfo* di;
989663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   struct _DebugInfoMapping *map = NULL;
990663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Word i;
991b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (di = debugInfo_list; di; di = di->next) {
992b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      vg_assert(di->fsm.filename);
993b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (di->have_dinfo)
994b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         continue; /* already have debuginfo for this object */
995b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (!di->fsm.have_ro_map)
996b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         continue; /* need to have a r-- mapping for this object */
997b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (di->fsm.have_rx_map)
998b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         continue; /* rx- mapping already exists */
999b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (!di->fsm.have_rw_map)
1000b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         continue; /* need to have a rw- mapping */
1001663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      /* Try to find a mapping matching the memory area. */
1002663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) {
1003663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         map = (struct _DebugInfoMapping*)VG_(indexXA)(di->fsm.maps, i);
1004663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         if (map->ro && map->avma == a && map->size == len)
1005663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            break;
1006663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         map = NULL;
1007663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      }
1008663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      if (!map)
1009663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         continue; /* this isn't an upgrade of an r-- mapping */
1010b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* looks like we're in luck! */
1011b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      break;
1012b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
1013b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (di == NULL)
1014b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return; /* didn't find anything */
1015b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1016663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* Do the upgrade.  Simply update the flags of the mapping
1017663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      and pretend we never saw the RO map at all. */
1018b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(di->fsm.have_ro_map);
1019663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   map->rx = True;
1020663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   map->ro = False;
1021b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   di->fsm.have_rx_map = True;
1022b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   di->fsm.have_ro_map = False;
1023663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* See if there are any more ro mappings */
1024663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) {
1025663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      map = (struct _DebugInfoMapping*)VG_(indexXA)(di->fsm.maps, i);
1026663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      if (map->ro) {
1027663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         di->fsm.have_ro_map = True;
1028663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         break;
1029663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      }
1030663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
1031663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
1032663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* Check if we're now in an accept state and read debuginfo.  Finally. */
1033663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if (di->fsm.have_rx_map && di->fsm.have_rw_map && !di->have_dinfo) {
1034663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      ULong di_handle __attribute__((unused))
1035663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         = di_notify_ACHIEVE_ACCEPT_STATE( di );
1036663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      /* di_handle is ignored. That's not a problem per se -- it just
1037663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         means nobody will ever be able to refer to this debuginfo by
1038663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         handle since nobody will know what the handle value is. */
1039663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
1040b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
1041b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1042b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------- PDB (windows debug info) reading --------- */
1044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* this should really return ULong, as per VG_(di_notify_mmap). */
1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(di_notify_pdb_debuginfo)( Int fd_obj, Addr avma_obj,
1047663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                   SizeT total_size, PtrdiffT bias_obj )
1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    i, r, sz_exename;
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong  obj_mtime, pdb_mtime;
1051436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   HChar  exename[VKI_PATH_MAX];
1052436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   HChar* pdbname = NULL;
1053436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   HChar* dot;
1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes sres;
1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    fd_pdbimage;
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SizeT  n_pdbimage;
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vg_stat stat_buf;
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > 0) {
1060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg, "\n");
1061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg,
1062b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         "LOAD_PDB_DEBUGINFO: clreq:   fd=%d, avma=%#lx, total_size=%lu, "
1063663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         "bias=%#lx\n",
1064663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         fd_obj, avma_obj, total_size, bias_obj
1065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
1066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 'fd' refers to the .exe/.dll we're dealing with.  Get its modification
1069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      time into obj_mtime. */
1070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   r = VG_(fstat)(fd_obj, &stat_buf);
1071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (r == -1)
1072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto out; /* stat failed ?! */
1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(r == 0);
1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   obj_mtime = stat_buf.mtime;
1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* and get its name into exename[]. */
1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VKI_PATH_MAX > 100); /* to ensure /proc/self/fd/%d is safe */
1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(exename, 0, sizeof(exename));
1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sprintf)(exename, "/proc/self/fd/%d", fd_obj);
1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* convert exename from a symlink to real name .. overwrites the
1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      old contents of the buffer.  Ick. */
1082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sz_exename = VG_(readlink)(exename, exename, sizeof(exename)-2 );
1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz_exename == -1)
1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto out; /* readlink failed ?! */
1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sz_exename >= 0 && sz_exename < sizeof(exename));
1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(exename[sizeof(exename)-1] == 0);
1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > 0) {
1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg, "LOAD_PDB_DEBUGINFO: objname: %s\n", exename);
1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Try to get the PDB file name from the executable. */
1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   pdbname = ML_(find_name_of_pdb_file)(exename);
1094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pdbname) {
1095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(VG_(strlen)(pdbname) >= 5); /* 5 = strlen("X.pdb") */
1096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* So we successfully extracted a name from the PE file.  But it's
1097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         likely to be of the form
1098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            e:\foo\bar\xyzzy\wibble.pdb
1099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         and we need to change it into something we can actually open
1100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         in Wine-world, which basically means turning it into
1101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $HOME/.wine/drive_e/foo/bar/xyzzy/wibble.pdb
1102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         We also take into account $WINEPREFIX, if it is set.
1103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         For the moment, if the name isn't fully qualified, just forget it
1104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (we'd have to root around to find where the pdb actually is)
1105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
1106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Change all the backslashes to forward slashes */
1107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; pdbname[i]; i++) {
1108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (pdbname[i] == '\\')
1109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            pdbname[i] = '/';
1110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool is_quald
1112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = ('a' <= VG_(tolower)(pdbname[0]) && VG_(tolower)(pdbname[0]) <= 'z')
1113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           && pdbname[1] == ':'
1114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           && pdbname[2] == '/';
1115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* home = VG_(getenv)("HOME");
1116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* wpfx = VG_(getenv)("WINEPREFIX");
1117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (is_quald && wpfx) {
1118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Change e:/foo/bar/xyzzy/wibble.pdb
1119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                to $WINEPREFIX/drive_e/foo/bar/xyzzy/wibble.pdb
1120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         */
1121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int mashedSzB = VG_(strlen)(pdbname) + VG_(strlen)(wpfx) + 50/*misc*/;
1122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar* mashed = ML_(dinfo_zalloc)("di.debuginfo.dnpdi.1", mashedSzB);
1123663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         VG_(snprintf)(mashed, mashedSzB, "%s/drive_%c%s",
1124663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                       wpfx, pdbname[0], &pdbname[2]);
1125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(mashed[mashedSzB-1] == 0);
1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ML_(dinfo_free)(pdbname);
1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         pdbname = mashed;
1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (is_quald && home && !wpfx) {
1130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Change e:/foo/bar/xyzzy/wibble.pdb
1131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                to $HOME/.wine/drive_e/foo/bar/xyzzy/wibble.pdb
1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         */
1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int mashedSzB = VG_(strlen)(pdbname) + VG_(strlen)(home) + 50/*misc*/;
1134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar* mashed = ML_(dinfo_zalloc)("di.debuginfo.dnpdi.2", mashedSzB);
1135663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         VG_(snprintf)(mashed, mashedSzB, "%s/.wine/drive_%c%s",
1136663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng		       home, pdbname[0], &pdbname[2]);
1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(mashed[mashedSzB-1] == 0);
1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ML_(dinfo_free)(pdbname);
1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         pdbname = mashed;
1140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* It's not a fully qualified path, or neither $HOME nor $WINE
1142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            are set (strange).  Give up. */
1143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ML_(dinfo_free)(pdbname);
1144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         pdbname = NULL;
1145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Try s/exe/pdb/ if we don't have a valid pdbname. */
1149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!pdbname) {
1150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Try to find a matching PDB file from which to read debuginfo.
1151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Windows PE files have symbol tables and line number information,
1152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         but MSVC doesn't seem to use them. */
1153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Why +5 ?  Because in the worst case, we could find a dot as the
1154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         last character of pdbname, and we'd then put "pdb" right after
1155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         it, hence extending it a bit. */
1156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pdbname = ML_(dinfo_zalloc)("di.debuginfo.lpd1", sz_exename+5);
1157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(strcpy)(pdbname, exename);
1158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(pdbname[sz_exename+5-1] == 0);
1159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dot = VG_(strrchr)(pdbname, '.');
1160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!dot)
1161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto out; /* there's no dot in the exe's name ?! */
1162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (dot[1] == 0)
1163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto out; /* hmm, path ends in "." */
1164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ('A' <= dot[1] && dot[1] <= 'Z')
1166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(strcpy)(dot, ".PDB");
1167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
1168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(strcpy)(dot, ".pdb");
1169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(pdbname[sz_exename+5-1] == 0);
1171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* See if we can find it, and check it's in-dateness. */
1174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sres = VG_(stat)(pdbname, &stat_buf);
1175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(sres)) {
1176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg, "Warning: Missing or un-stat-able %s\n",
1177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               pdbname);
1178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > 0)
1179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg, "LOAD_PDB_DEBUGINFO: missing: %s\n", pdbname);
1180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto out;
1181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   pdb_mtime = stat_buf.mtime;
1183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (obj_mtime > pdb_mtime + 60ULL) {
1185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* PDB file is older than PE file.  Really, the PDB should be
1186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         newer than the PE, but that doesn't always seem to be the
1187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case.  Allow the PDB to be up to one minute older.
1188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Otherwise, it's probably out of date, in which case ignore it
1189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         or we will either (a) print wrong stack traces or more likely
1190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (b) crash.
1191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
1192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg,
1193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   "Warning:       %s (mtime = %llu)\n"
1194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   " is older than %s (mtime = %llu)\n",
1195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   pdbname, pdb_mtime, exename, obj_mtime);
1196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sres = VG_(open)(pdbname, VKI_O_RDONLY, 0);
1199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(sres)) {
1200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg, "Warning: Can't open %s\n", pdbname);
1201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto out;
1202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1204b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Looks promising; go on to try and read stuff from it.  But don't
1205b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      mmap the file.  Instead mmap free space and read the file into
1206b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      it.  This is because files on CIFS filesystems that are mounted
1207b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      '-o directio' can't be mmap'd, and that mount option is needed
1208b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      to make CIFS work reliably.  (See
1209b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      http://www.nabble.com/Corrupted-data-on-write-to-
1210b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                            Windows-2003-Server-t2782623.html)
1211b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      This is slower, but at least it works reliably. */
1212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fd_pdbimage = sr_Res(sres);
1213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_pdbimage  = stat_buf.size;
1214b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (n_pdbimage == 0 || n_pdbimage > 0x7FFFFFFF) {
1215b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      // 0x7FFFFFFF: why?  Because the VG_(read) just below only
1216b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      // can deal with a signed int as the size of data to read,
1217b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      // so we can't reliably check for read failure for files
1218b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      // greater than that size.  Hence just skip them; we're
1219b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      // unlikely to encounter a PDB that large anyway.
1220b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(close)(fd_pdbimage);
1221b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      goto out;
1222b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
1223b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   sres = VG_(am_mmap_anon_float_valgrind)( n_pdbimage );
1224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(sres)) {
1225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(close)(fd_pdbimage);
1226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto out;
1227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1229b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   void* pdbimage = (void*)sr_Res(sres);
1230b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   r = VG_(read)( fd_pdbimage, pdbimage, (Int)n_pdbimage );
1231b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (r < 0 || r != (Int)n_pdbimage) {
1232b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(am_munmap_valgrind)( (Addr)pdbimage, n_pdbimage );
1233b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(close)(fd_pdbimage);
1234b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      goto out;
1235b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
1236b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > 0)
1238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg, "LOAD_PDB_DEBUGINFO: pdbname: %s\n", pdbname);
1239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* play safe; always invalidate the CFI cache.  I don't know if
1241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      this is necessary, but anyway .. */
1242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cfsi_cache__invalidate();
1243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* dump old info for this range, if any */
1244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   discard_syms_in_range( avma_obj, total_size );
1245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1246b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   { DebugInfo* di = find_or_create_DebugInfo_for(exename);
1247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* this di must be new, since we just nuked any old stuff in the range */
1249b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     vg_assert(di && !di->fsm.have_rx_map && !di->fsm.have_rw_map);
1250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vg_assert(!di->have_dinfo);
1251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* don't set up any of the di-> fields; let
1253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        ML_(read_pdb_debug_info) do it. */
1254663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng     ML_(read_pdb_debug_info)( di, avma_obj, bias_obj,
1255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               pdbimage, n_pdbimage, pdbname, pdb_mtime );
1256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     // JRS fixme: take notice of return value from read_pdb_debug_info,
1257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     // and handle failure
1258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vg_assert(di->have_dinfo); // fails if PDB read failed
1259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     VG_(am_munmap_valgrind)( (Addr)pdbimage, n_pdbimage );
1260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     VG_(close)(fd_pdbimage);
1261b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1262b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     if (VG_(clo_verbosity) > 0) {
1263b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        VG_(message)(Vg_UserMsg, "LOAD_PDB_DEBUGINFO: done:    "
1264b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 "%lu syms, %lu src locs, %lu fpo recs\n",
1265b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     di->symtab_used, di->loctab_used, di->fpo_size);
1266b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     }
1267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  out:
1270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pdbname) ML_(dinfo_free)(pdbname);
1271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif /* defined(VGO_linux) || defined(VGO_darwin) */
1274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                      ---*/
1278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- TOP LEVEL: QUERYING EXISTING DEBUG INFO              ---*/
1279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                      ---*/
1280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(di_discard_ALL_debuginfo)( void )
1283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo *di, *di2;
1285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   di = debugInfo_list;
1286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (di) {
1287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di2 = di->next;
1288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("XXX rm %p\n", di);
1289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      free_DebugInfo( di );
1290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di = di2;
1291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1295663860b1408516d02ebfcb3a9999a134e6cfb223Ben Chengstruct _DebugInfoMapping* ML_(find_rx_mapping) ( struct _DebugInfo* di,
1296663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                                 Addr lo, Addr hi )
1297663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng{
1298663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Word i;
1299663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vg_assert(lo <= hi);
1300663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
1301663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* Optimization: Try to use the last matched rx mapping first */
1302663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if (   di->last_rx_map
1303663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng       && lo >= di->last_rx_map->avma
1304663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng       && hi <  di->last_rx_map->avma + di->last_rx_map->size)
1305663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      return di->last_rx_map;
1306663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
1307663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) {
1308663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      struct _DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i);
1309663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      if (   map->rx && map->size > 0
1310663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng          && lo >= map->avma && hi < map->avma + map->size) {
1311663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         di->last_rx_map = map;
1312663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         return map;
1313663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      }
1314663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
1315663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
1316663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   return NULL;
1317663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng}
1318663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
1319663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
1320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Use of symbol table & location info to create        ---*/
1322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- plausible-looking stack dumps.                       ---*/
1323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Search all symtabs that we know about to locate ptr.  If found, set
1326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *pdi to the relevant DebugInfo, and *symno to the symtab entry
1327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *number within that.  If not found, *psi is set to NULL.
1328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If findText==True,  only text symbols are searched for.
1329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If findText==False, only data symbols are searched for.
1330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void search_all_symtabs ( Addr ptr, /*OUT*/DebugInfo** pdi,
1332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           /*OUT*/Word* symno,
1333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Bool match_anywhere_in_sym,
1334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Bool findText )
1335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word       sno;
1337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* di;
1338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool       inRange;
1339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (di = debugInfo_list; di != NULL; di = di->next) {
1341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (findText) {
1343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Consider any symbol in the r-x mapped area to be text.
1344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            See Comment_Regarding_Text_Range_Checks in storage.c for
1345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            details. */
1346b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         inRange = di->fsm.have_rx_map
1347663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                   && (ML_(find_rx_mapping)(di, ptr, ptr) != NULL);
1348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         inRange = (di->data_present
1350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    && di->data_size > 0
1351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    && di->data_avma <= ptr
1352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    && ptr < di->data_avma + di->data_size)
1353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ||
1354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   (di->sdata_present
1355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    && di->sdata_size > 0
1356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    && di->sdata_avma <= ptr
1357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    && ptr < di->sdata_avma + di->sdata_size)
1358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ||
1359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   (di->bss_present
1360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    && di->bss_size > 0
1361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    && di->bss_avma <= ptr
1362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    && ptr < di->bss_avma + di->bss_size)
1363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ||
1364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   (di->sbss_present
1365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    && di->sbss_size > 0
1366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    && di->sbss_avma <= ptr
1367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    && ptr < di->sbss_avma + di->sbss_size)
1368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ||
1369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   (di->rodata_present
1370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    && di->rodata_size > 0
1371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    && di->rodata_avma <= ptr
1372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    && ptr < di->rodata_avma + di->rodata_size);
1373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!inRange) continue;
1376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sno = ML_(search_one_symtab) (
1378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               di, ptr, match_anywhere_in_sym, findText );
1379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sno == -1) goto not_found;
1380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *symno = sno;
1381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *pdi = di;
1382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
1383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  not_found:
1386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *pdi = NULL;
1387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Search all loctabs that we know about to locate ptr.  If found, set
1391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *pdi to the relevant DebugInfo, and *locno to the loctab entry
1392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *number within that.  If not found, *pdi is set to NULL. */
1393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void search_all_loctabs ( Addr ptr, /*OUT*/DebugInfo** pdi,
1394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           /*OUT*/Word* locno )
1395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word       lno;
1397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* di;
1398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (di = debugInfo_list; di != NULL; di = di->next) {
1399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di->text_present
1400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && di->text_size > 0
1401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && di->text_avma <= ptr
1402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && ptr < di->text_avma + di->text_size) {
1403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lno = ML_(search_one_loctab) ( di, ptr );
1404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (lno == -1) goto not_found;
1405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *locno = lno;
1406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *pdi = di;
1407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return;
1408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  not_found:
1411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *pdi = NULL;
1412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The whole point of this whole big deal: map a code address to a
1416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   plausible symbol name.  Returns False if no idea; otherwise True.
1417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Caller supplies buf and nbuf.  If do_cxx_demangling is False, don't do
1418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   C++ demangling, regardless of VG_(clo_demangle) -- probably because the
1419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call has come from VG_(get_fnname_raw)().  findText
1420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   indicates whether we're looking for a text symbol or a data symbol
1421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   -- caller must choose one kind or the other. */
1422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool get_sym_name ( Bool do_cxx_demangling, Bool do_z_demangling,
1424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool do_below_main_renaming,
1425436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                    Addr a, HChar* buf, Int nbuf,
1426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool match_anywhere_in_sym, Bool show_offset,
1427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool findText, /*OUT*/PtrdiffT* offsetP )
1428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* di;
1430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word       sno;
1431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   PtrdiffT   offset;
1432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   search_all_symtabs ( a, &di, &sno, match_anywhere_in_sym, findText );
1434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (di == NULL)
1435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
1436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1437b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(di->symtab[sno].pri_name);
1438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(demangle) ( do_cxx_demangling, do_z_demangling,
1439b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   di->symtab[sno].pri_name, buf, nbuf );
1440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Do the below-main hack */
1442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // To reduce the endless nuisance of multiple different names
1443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // for "the frame below main()" screwing up the testsuite, change all
1444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // known incarnations of said into a single name, "(below main)", if
1445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // --show-below-main=yes.
1446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( do_below_main_renaming && ! VG_(clo_show_below_main) &&
1447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        Vg_FnNameBelowMain == VG_(get_fnname_kind)(buf) )
1448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
1449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(strncpy_safely)(buf, "(below main)", nbuf);
1450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   offset = a - di->symtab[sno].addr;
1452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (offsetP) *offsetP = offset;
1453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (show_offset && offset != 0) {
1455436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      HChar    buf2[12];
1456436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      HChar*   symend = buf + VG_(strlen)(buf);
1457436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      HChar*   end = buf + nbuf;
1458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int      len;
1459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      len = VG_(sprintf)(buf2, "%c%ld",
1461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			 offset < 0 ? '-' : '+',
1462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			 offset < 0 ? -offset : offset);
1463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(len < (Int)sizeof(buf2));
1464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (len < (end - symend)) {
1466436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	 HChar *cp = buf2;
1467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 VG_(memcpy)(symend, cp, len+1);
1468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   buf[nbuf-1] = 0; /* paranoia */
1472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
1474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ppc64-linux only: find the TOC pointer (R2 value) that should be in
1477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   force at the entry point address of the function containing
1478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   guest_code_addr.  Returns 0 if not known. */
1479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownAddr VG_(get_tocptr) ( Addr guest_code_addr )
1480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* si;
1482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word       sno;
1483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   search_all_symtabs ( guest_code_addr,
1484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        &si, &sno,
1485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        True/*match_anywhere_in_fun*/,
1486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        True/*consider text symbols only*/ );
1487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (si == NULL)
1488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 0;
1489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
1490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return si->symtab[sno].tocptr;
1491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is available to tools... always demangle C++ names,
1494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   match anywhere in function, but don't show offsets. */
1495436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovBool VG_(get_fnname) ( Addr a, HChar* buf, Int nbuf )
1496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return get_sym_name ( /*C++-demangle*/True, /*Z-demangle*/True,
1498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*below-main-renaming*/True,
1499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         a, buf, nbuf,
1500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*match_anywhere_in_fun*/True,
1501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*show offset?*/False,
1502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*text syms only*/True,
1503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*offsetP*/NULL );
1504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is available to tools... always demangle C++ names,
1507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   match anywhere in function, and show offset if nonzero. */
1508436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovBool VG_(get_fnname_w_offset) ( Addr a, HChar* buf, Int nbuf )
1509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return get_sym_name ( /*C++-demangle*/True, /*Z-demangle*/True,
1511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*below-main-renaming*/True,
1512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         a, buf, nbuf,
1513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*match_anywhere_in_fun*/True,
1514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*show offset?*/True,
1515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*text syms only*/True,
1516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*offsetP*/NULL );
1517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is available to tools... always demangle C++ names,
1520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   only succeed if 'a' matches first instruction of function,
1521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and don't show offsets. */
1522436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovBool VG_(get_fnname_if_entry) ( Addr a, HChar* buf, Int nbuf )
1523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return get_sym_name ( /*C++-demangle*/True, /*Z-demangle*/True,
1525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*below-main-renaming*/True,
1526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         a, buf, nbuf,
1527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*match_anywhere_in_fun*/False,
1528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*show offset?*/False,
1529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*text syms only*/True,
1530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*offsetP*/NULL );
1531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is only available to core... don't C++-demangle, don't Z-demangle,
1534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   don't rename below-main, match anywhere in function, and don't show
1535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   offsets. */
1536436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovBool VG_(get_fnname_raw) ( Addr a, HChar* buf, Int nbuf )
1537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return get_sym_name ( /*C++-demangle*/False, /*Z-demangle*/False,
1539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*below-main-renaming*/False,
1540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         a, buf, nbuf,
1541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*match_anywhere_in_fun*/True,
1542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*show offset?*/False,
1543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*text syms only*/True,
1544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*offsetP*/NULL );
1545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is only available to core... don't demangle C++ names, but do
1548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do Z-demangling and below-main-renaming, match anywhere in function, and
1549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   don't show offsets. */
1550436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovBool VG_(get_fnname_no_cxx_demangle) ( Addr a, HChar* buf, Int nbuf )
1551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return get_sym_name ( /*C++-demangle*/False, /*Z-demangle*/True,
1553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*below-main-renaming*/True,
1554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         a, buf, nbuf,
1555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*match_anywhere_in_fun*/True,
1556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*show offset?*/False,
1557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*text syms only*/True,
1558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*offsetP*/NULL );
1559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1561663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng/* mips-linux only: find the offset of current address. This is needed for
1562663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   stack unwinding for MIPS.
1563663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng*/
1564663860b1408516d02ebfcb3a9999a134e6cfb223Ben ChengBool VG_(get_inst_offset_in_function)( Addr a,
1565663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                       /*OUT*/PtrdiffT* offset )
1566663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng{
1567436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   HChar fnname[64];
1568663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   return get_sym_name ( /*C++-demangle*/False, /*Z-demangle*/False,
1569663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                         /*below-main-renaming*/False,
1570663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                         a, fnname, 64,
1571663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                         /*match_anywhere_in_sym*/True,
1572663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                         /*show offset?*/True,
1573663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                         /*data syms only please*/True,
1574663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                         offset );
1575663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng}
1576663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
1577436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovVg_FnNameKind VG_(get_fnname_kind) ( HChar* name )
1578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_STREQ("main", name)) {
1580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return Vg_FnNameMain;
1581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else if (
1583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#      if defined(VGO_linux)
1584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       VG_STREQ("__libc_start_main",  name) ||  // glibc glibness
1585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       VG_STREQ("generic_start_main", name) ||  // Yellow Dog doggedness
1586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#      elif defined(VGO_darwin)
1587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       // See readmacho.c for an explanation of this.
1588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       VG_STREQ("start_according_to_valgrind", name) ||  // Darwin, darling
1589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#      else
1590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#        error "Unknown OS"
1591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#      endif
1592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       0) {
1593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return Vg_FnNameBelowMain;
1594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return Vg_FnNameNormal;
1597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownVg_FnNameKind VG_(get_fnname_kind_from_IP) ( Addr ip )
1601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // We don't need a big buffer;  all the special names are small.
1603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   #define BUFLEN 50
1604436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   HChar buf[50];
1605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // We don't demangle, because it's faster not to, and the special names
1607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // we're looking for won't be demangled.
1608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(get_fnname_raw) ( ip, buf, BUFLEN )) {
1609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      buf[BUFLEN-1] = '\0';      // paranoia
1610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return VG_(get_fnname_kind)(buf);
1611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return Vg_FnNameNormal;    // Don't know the name, treat it as normal.
1613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Looks up data_addr in the collection of data symbols, and if found
1617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   puts its name (or as much as will fit) into dname[0 .. n_dname-1],
1618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   which is guaranteed to be zero terminated.  Also data_addr's offset
1619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   from the symbol start is put into *offset. */
1620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(get_datasym_and_offset)( Addr data_addr,
1621436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                  /*OUT*/HChar* dname, Int n_dname,
1622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  /*OUT*/PtrdiffT* offset )
1623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool ok;
1625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(n_dname > 1);
1626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ok = get_sym_name ( /*C++-demangle*/False, /*Z-demangle*/False,
1627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       /*below-main-renaming*/False,
1628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       data_addr, dname, n_dname,
1629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       /*match_anywhere_in_sym*/True,
1630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       /*show offset?*/False,
1631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       /*data syms only please*/False,
1632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       offset );
1633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!ok)
1634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
1635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dname[n_dname-1] = 0;
1636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
1637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Map a code address to the name of a shared object file or the
1640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   executable.  Returns False if no idea; otherwise True.  Doesn't
1641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   require debug info.  Caller supplies buf and nbuf. */
1642436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovBool VG_(get_objname) ( Addr a, HChar* buf, Int nbuf )
1643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* di;
1645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const NSegment *seg;
1646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar* filename;
1647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(nbuf > 0);
1648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Look in the debugInfo_list to find the name.  In most cases we
1649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      expect this to produce a result. */
1650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (di = debugInfo_list; di != NULL; di = di->next) {
1651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di->text_present
1652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && di->text_size > 0
1653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && di->text_avma <= a
1654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a < di->text_avma + di->text_size) {
1655b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(strncpy_safely)(buf, di->fsm.filename, nbuf);
1656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         buf[nbuf-1] = 0;
1657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
1658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Last-ditch fallback position: if we don't find the address in
1661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the debugInfo_list, ask the address space manager whether it
1662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      knows the name of the file associated with this mapping.  This
1663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      allows us to print the names of exe/dll files in the stack trace
1664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      when running programs under wine. */
1665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( (seg = VG_(am_find_nsegment(a))) != NULL
1666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && (filename = VG_(am_get_filename)(seg)) != NULL ) {
1667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(strncpy_safely)(buf, filename, nbuf);
1668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
1669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
1671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Map a code address to its DebugInfo.  Returns NULL if not found.  Doesn't
1674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   require debug info. */
1675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownDebugInfo* VG_(find_DebugInfo) ( Addr a )
1676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static UWord n_search = 0;
1678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* di;
1679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_search++;
1680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (di = debugInfo_list; di != NULL; di = di->next) {
1681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di->text_present
1682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && di->text_size > 0
1683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && di->text_avma <= a
1684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a < di->text_avma + di->text_size) {
1685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (0 == (n_search & 0xF))
1686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            move_DebugInfo_one_step_forward( di );
1687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return di;
1688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return NULL;
1691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Map a code address to a filename.  Returns True if successful.  */
1694436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovBool VG_(get_filename)( Addr a, HChar* filename, Int n_filename )
1695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* si;
1697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word       locno;
1698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   search_all_loctabs ( a, &si, &locno );
1699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (si == NULL)
1700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
1701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(strncpy_safely)(filename, si->loctab[locno].filename, n_filename);
1702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
1703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Map a code address to a line number.  Returns True if successful. */
1706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(get_linenum)( Addr a, UInt* lineno )
1707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* si;
1709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word       locno;
1710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   search_all_loctabs ( a, &si, &locno );
1711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (si == NULL)
1712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
1713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *lineno = si->loctab[locno].lineno;
1714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
1716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Map a code address to a filename/line number/dir name info.
1719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   See prototype for detailed description of behaviour.
1720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(get_filename_linenum) ( Addr a,
1722436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 /*OUT*/HChar* filename, Int n_filename,
1723436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                 /*OUT*/HChar* dirname,  Int n_dirname,
1724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 /*OUT*/Bool* dirname_available,
1725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 /*OUT*/UInt* lineno )
1726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* si;
1728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word       locno;
1729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert( (dirname == NULL && dirname_available == NULL)
1731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              ||
1732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              (dirname != NULL && dirname_available != NULL) );
1733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   search_all_loctabs ( a, &si, &locno );
1735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (si == NULL) {
1736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (dirname_available) {
1737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *dirname_available = False;
1738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *dirname = 0;
1739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
1741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(strncpy_safely)(filename, si->loctab[locno].filename, n_filename);
1744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *lineno = si->loctab[locno].lineno;
1745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (dirname) {
1747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* caller wants directory info too .. */
1748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(n_dirname > 0);
1749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (si->loctab[locno].dirname) {
1750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* .. and we have some */
1751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *dirname_available = True;
1752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(strncpy_safely)(dirname, si->loctab[locno].dirname,
1753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      n_dirname);
1754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* .. but we don't have any */
1756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *dirname_available = False;
1757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *dirname = 0;
1758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
1762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Map a function name to its entry point and toc pointer.  Is done by
1766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sequential search of all symbol tables, so is very slow.  To
1767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mitigate the worst performance effects, you may specify a soname
1768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   pattern, and only objects matching that pattern are searched.
1769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Therefore specify "*" to search all the objects.  On TOC-afflicted
1770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   platforms, a symbol is deemed to be found only if it has a nonzero
1771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TOC pointer.  */
1772436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovBool VG_(lookup_symbol_SLOW)(const HChar* sopatt, HChar* name,
1773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             Addr* pEnt, Addr* pToc)
1774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool     require_pToc = False;
1776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int      i;
1777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* si;
1778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool     debug = False;
1779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VG_PLAT_USES_PPCTOC)
1780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   require_pToc = True;
1781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (si = debugInfo_list; si; si = si->next) {
1783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (debug)
1784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("lookup_symbol_SLOW: considering %s\n", si->soname);
1785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!VG_(string_match)(sopatt, si->soname)) {
1786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (debug)
1787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(printf)(" ... skip\n");
1788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
1789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < si->symtab_used; i++) {
1791436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         HChar* pri_name = si->symtab[i].pri_name;
1792b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         tl_assert(pri_name);
1793b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (0==VG_(strcmp)(name, pri_name)
1794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && (require_pToc ? si->symtab[i].tocptr : True)) {
1795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *pEnt = si->symtab[i].addr;
1796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *pToc = si->symtab[i].tocptr;
1797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
1798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1799436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         HChar** sec_names = si->symtab[i].sec_names;
1800b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (sec_names) {
1801b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            tl_assert(sec_names[0]);
1802b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            while (*sec_names) {
1803b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               if (0==VG_(strcmp)(name, *sec_names)
1804b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   && (require_pToc ? si->symtab[i].tocptr : True)) {
1805b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  *pEnt = si->symtab[i].addr;
1806b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  *pToc = si->symtab[i].tocptr;
1807b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  return True;
1808b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               }
1809b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               sec_names++;
1810b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            }
1811b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
1812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
1815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* VG_(describe_IP): print into buf info on code address, function
1819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   name and filename. */
1820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Copy str into buf starting at n, but not going past buf[n_buf-1]
1822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and always ensuring that buf is zero-terminated. */
1823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1824436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Int putStr ( Int n, Int n_buf, HChar* buf, const HChar* str )
1825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(n_buf > 0);
1827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(n >= 0 && n < n_buf);
1828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (; n < n_buf-1 && *str != 0; n++,str++)
1829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      buf[n] = *str;
1830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(n >= 0 && n < n_buf);
1831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   buf[n] = '\0';
1832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return n;
1833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Same as putStr, but escaping chars for XML output, and
1836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   also not adding more than count chars to n_buf. */
1837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1838436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Int putStrEsc ( Int n, Int n_buf, Int count, HChar* buf, HChar* str )
1839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1840436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   HChar alt[2];
1841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(n_buf > 0);
1842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(count >= 0 && count < n_buf);
1843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(n >= 0 && n < n_buf);
1844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (; *str != 0; str++) {
1845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(count >= 0);
1846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (count <= 0)
1847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto done;
1848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (*str) {
1849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case '&':
1850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (count < 5) goto done;
1851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            n = putStr( n, n_buf, buf, "&amp;");
1852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            count -= 5;
1853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
1854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case '<':
1855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (count < 4) goto done;
1856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            n = putStr( n, n_buf, buf, "&lt;");
1857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            count -= 4;
1858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
1859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case '>':
1860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (count < 4) goto done;
1861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            n = putStr( n, n_buf, buf, "&gt;");
1862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            count -= 4;
1863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
1864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
1865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (count < 1) goto done;
1866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            alt[0] = *str;
1867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            alt[1] = 0;
1868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            n = putStr( n, n_buf, buf, alt );
1869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            count -= 1;
1870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
1871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  done:
1874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(count >= 0); /* should not go -ve in loop */
1875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(n >= 0 && n < n_buf);
1876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return n;
1877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1879436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovHChar* VG_(describe_IP)(Addr eip, HChar* buf, Int n_buf)
1880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define APPEND(_str) \
1882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n = putStr(n, n_buf, buf, _str)
1883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define APPEND_ESC(_count,_str) \
1884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n = putStrEsc(n, n_buf, (_count), buf, (_str))
1885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define BUF_LEN    4096
1886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt  lineno;
1888436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   HChar ibuf[50];
1889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   n = 0;
1890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1891436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   static HChar buf_fn[BUF_LEN];
1892436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   static HChar buf_obj[BUF_LEN];
1893436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   static HChar buf_srcloc[BUF_LEN];
1894436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   static HChar buf_dirname[BUF_LEN];
1895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   buf_fn[0] = buf_obj[0] = buf_srcloc[0] = buf_dirname[0] = 0;
1896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool  know_dirinfo = False;
1898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool  know_fnname  = VG_(clo_sym_offsets)
1899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        ? VG_(get_fnname_w_offset) (eip, buf_fn, BUF_LEN)
1900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        : VG_(get_fnname) (eip, buf_fn, BUF_LEN);
1901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool  know_objname = VG_(get_objname)(eip, buf_obj, BUF_LEN);
1902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool  know_srcloc  = VG_(get_filename_linenum)(
1903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           eip,
1904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           buf_srcloc,  BUF_LEN,
1905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           buf_dirname, BUF_LEN, &know_dirinfo,
1906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           &lineno
1907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        );
1908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   buf_fn     [ sizeof(buf_fn)-1      ]  = 0;
1909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   buf_obj    [ sizeof(buf_obj)-1     ]  = 0;
1910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   buf_srcloc [ sizeof(buf_srcloc)-1  ]  = 0;
1911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   buf_dirname[ sizeof(buf_dirname)-1 ]  = 0;
1912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_xml)) {
1914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   human_readable = True;
1916436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar* maybe_newline  = human_readable ? "\n      " : "";
1917436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar* maybe_newline2 = human_readable ? "\n    "   : "";
1918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Print in XML format, dumping in as much info as we know.
1920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Ensure all tags are balanced even if the individual strings
1921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         are too long.  Allocate 1/10 of BUF_LEN to the object name,
1922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         6/10s to the function name, 1/10 to the directory name and
1923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         1/10 to the file name, leaving 1/10 for all the fixed-length
1924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stuff. */
1925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      APPEND("<frame>");
1926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(sprintf)(ibuf,"<ip>0x%llX</ip>", (ULong)eip);
1927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      APPEND(maybe_newline);
1928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      APPEND(ibuf);
1929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (know_objname) {
1930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND(maybe_newline);
1931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND("<obj>");
1932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND_ESC(1*BUF_LEN/10, buf_obj);
1933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND("</obj>");
1934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (know_fnname) {
1936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND(maybe_newline);
1937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND("<fn>");
1938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND_ESC(6*BUF_LEN/10, buf_fn);
1939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND("</fn>");
1940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (know_srcloc) {
1942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (know_dirinfo) {
1943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            APPEND(maybe_newline);
1944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            APPEND("<dir>");
1945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            APPEND_ESC(1*BUF_LEN/10, buf_dirname);
1946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            APPEND("</dir>");
1947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND(maybe_newline);
1949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND("<file>");
1950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND_ESC(1*BUF_LEN/10, buf_srcloc);
1951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND("</file>");
1952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND(maybe_newline);
1953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND("<line>");
1954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(sprintf)(ibuf,"%d",lineno);
1955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND(ibuf);
1956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND("</line>");
1957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      APPEND(maybe_newline2);
1959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      APPEND("</frame>");
1960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Print for humans to read */
1964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //
1965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Possible forms:
1966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //
1967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //   0x80483BF: really (a.c:20)
1968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //   0x80483BF: really (in /foo/a.out)
1969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //   0x80483BF: really (in ???)
1970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //   0x80483BF: ??? (in /foo/a.out)
1971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //   0x80483BF: ??? (a.c:20)
1972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //   0x80483BF: ???
1973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //
1974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(sprintf)(ibuf,"0x%llX: ", (ULong)eip);
1975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      APPEND(ibuf);
1976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (know_fnname) {
1977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND(buf_fn);
1978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND("???");
1980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (know_srcloc) {
1982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND(" (");
1983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Get the directory name, if any, possibly pruned, into dirname.
1984436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         HChar* dirname = NULL;
1985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (VG_(clo_n_fullpath_after) > 0) {
1986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Int i;
1987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dirname = buf_dirname;
1988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // Remove leading prefixes from the dirname.
1989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // If user supplied --fullpath-after=foo, this will remove
1990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // a leading string which matches '.*foo' (not greedy).
1991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for (i = 0; i < VG_(clo_n_fullpath_after); i++) {
1992436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               const HChar* prefix = VG_(clo_fullpath_after)[i];
1993436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               HChar* str    = VG_(strstr)(dirname, prefix);
1994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (str) {
1995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  dirname = str + VG_(strlen)(prefix);
1996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
1997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
1998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* remove leading "./" */
2000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (dirname[0] == '.' && dirname[1] == '/')
2001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dirname += 2;
2002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // do we have any interesting directory name to show?  If so
2004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // add it in.
2005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (dirname && dirname[0] != 0) {
2006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            APPEND(dirname);
2007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            APPEND("/");
2008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND(buf_srcloc);
2010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND(":");
2011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(sprintf)(ibuf,"%d",lineno);
2012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND(ibuf);
2013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND(")");
2014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else if (know_objname) {
2015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND(" (in ");
2016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND(buf_obj);
2017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND(")");
2018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else if (know_fnname) {
2019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Nb: do this in two steps because "??)" is a trigraph!
2020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND(" (in ???");
2021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         APPEND(")");
2022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return buf;
2026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef APPEND
2028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef APPEND_ESC
2029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef BUF_LEN
2030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------*/
2034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                        ---*/
2035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- TOP LEVEL: FOR UNWINDING THE STACK USING               ---*/
2036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---            DWARF3 .eh_frame INFO                       ---*/
2037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                        ---*/
2038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------*/
2039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Gather up all the constant pieces of info needed to evaluate
2041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   a CfiExpr into one convenient struct. */
2042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
2043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct {
2044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      D3UnwindRegs* uregs;
2045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr          min_accessible;
2046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr          max_accessible;
2047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CfiExprEvalContext;
2049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Evaluate the CfiExpr rooted at ix in exprs given the context eec.
2051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *ok is set to False on failure, but not to True on success.  The
2052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   caller must set it to True before calling. */
2053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noinline))
2054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUWord evalCfiExpr ( XArray* exprs, Int ix,
2056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    CfiExprEvalContext* eec, Bool* ok )
2057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2058436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   UWord w, wL, wR;
2059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr  a;
2060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CfiExpr* e;
2061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sizeof(Addr) == sizeof(UWord));
2062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   e = VG_(indexXA)( exprs, ix );
2063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (e->tag) {
2064436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case Cex_Unop:
2065436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         w = evalCfiExpr( exprs, e->Cex.Unop.ix, eec, ok );
2066436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         if (!(*ok)) return 0;
2067436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         switch (e->Cex.Unop.op) {
2068436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case Cunop_Abs: return (Word) w < 0 ? - w : w;
2069436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case Cunop_Neg: return - (Word) w;
2070436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case Cunop_Not: return ~ w;
2071436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            default: goto unhandled;
2072436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         }
2073436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         /*NOTREACHED*/
2074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Cex_Binop:
2075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wL = evalCfiExpr( exprs, e->Cex.Binop.ixL, eec, ok );
2076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!(*ok)) return 0;
2077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wR = evalCfiExpr( exprs, e->Cex.Binop.ixR, eec, ok );
2078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!(*ok)) return 0;
2079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (e->Cex.Binop.op) {
2080436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case Cbinop_Add: return wL + wR;
2081436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case Cbinop_Sub: return wL - wR;
2082436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case Cbinop_And: return wL & wR;
2083436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case Cbinop_Mul: return wL * wR;
2084436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case Cbinop_Shl: return wL << wR;
2085436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case Cbinop_Shr: return wL >> wR;
2086436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case Cbinop_Eq: return wL == wR ? 1 : 0;
2087436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case Cbinop_Ge: return (Word) wL >= (Word) wR ? 1 : 0;
2088436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case Cbinop_Gt: return (Word) wL > (Word) wR ? 1 : 0;
2089436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case Cbinop_Le: return (Word) wL <= (Word) wR ? 1 : 0;
2090436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case Cbinop_Lt: return (Word) wL < (Word) wR ? 1 : 0;
2091436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case Cbinop_Ne: return wL != wR ? 1 : 0;
2092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default: goto unhandled;
2093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/
2095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Cex_CfiReg:
2096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (e->Cex.CfiReg.reg) {
2097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#           if defined(VGA_x86) || defined(VGA_amd64)
2098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case Creg_IA_IP: return eec->uregs->xip;
2099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case Creg_IA_SP: return eec->uregs->xsp;
2100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case Creg_IA_BP: return eec->uregs->xbp;
2101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#           elif defined(VGA_arm)
2102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case Creg_ARM_R15: return eec->uregs->r15;
2103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case Creg_ARM_R14: return eec->uregs->r14;
2104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case Creg_ARM_R13: return eec->uregs->r13;
2105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case Creg_ARM_R12: return eec->uregs->r12;
2106b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#           elif defined(VGA_s390x)
2107b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case Creg_IA_IP: return eec->uregs->ia;
2108b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case Creg_IA_SP: return eec->uregs->sp;
2109b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case Creg_IA_BP: return eec->uregs->fp;
2110b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case Creg_S390_R14: return eec->uregs->lr;
2111436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#           elif defined(VGA_mips32) || defined(VGA_mips64)
2112663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            case Creg_IA_IP: return eec->uregs->pc;
2113663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            case Creg_IA_SP: return eec->uregs->sp;
2114663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            case Creg_IA_BP: return eec->uregs->fp;
2115663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            case Creg_MIPS_RA: return eec->uregs->ra;
2116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#           elif defined(VGA_ppc32) || defined(VGA_ppc64)
2117436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#           elif defined(VGP_arm64_linux)
2118436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            case Creg_ARM64_X30: return eec->uregs->x30;
2119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#           else
2120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#             error "Unsupported arch"
2121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#           endif
2122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default: goto unhandled;
2123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/
2125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Cex_Const:
2126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return e->Cex.Const.con;
2127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Cex_Deref:
2128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         a = evalCfiExpr( exprs, e->Cex.Deref.ixAddr, eec, ok );
2129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!(*ok)) return 0;
2130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (a < eec->min_accessible
2131b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov             || a > eec->max_accessible - sizeof(UWord) + 1) {
2132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *ok = False;
2133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return 0;
2134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* let's hope it doesn't trap! */
2136b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         return ML_(read_UWord)((void *)a);
2137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
2138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto unhandled;
2139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*NOTREACHED*/
2141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  unhandled:
2142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("\n\nevalCfiExpr: unhandled\n");
2143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ML_(ppCfiExpr)( exprs, ix );
2144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("\n");
2145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(0);
2146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*NOTREACHED*/
2147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 0;
2148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Search all the DebugInfos in the entire system, to find the DiCfSI
2152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   that pertains to 'ip'.
2153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If found, set *diP to the DebugInfo in which it resides, and
2155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *ixP to the index in that DebugInfo's cfsi array.
2156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If not found, set *diP to (DebugInfo*)1 and *ixP to zero.
2158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noinline))
2160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void find_DiCfSI ( /*OUT*/DebugInfo** diP,
2161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          /*OUT*/Word* ixP,
2162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          Addr ip )
2163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* di;
2165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word       i = -1;
2166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static UWord n_search = 0;
2168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static UWord n_steps = 0;
2169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_search++;
2170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) VG_(printf)("search for %#lx\n", ip);
2172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (di = debugInfo_list; di != NULL; di = di->next) {
2174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Word j;
2175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_steps++;
2176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Use the per-DebugInfo summary address ranges to skip
2178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         inapplicable DebugInfos quickly. */
2179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di->cfsi_used == 0)
2180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
2181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ip < di->cfsi_minavma || ip > di->cfsi_maxavma)
2182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
2183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* It might be in this DebugInfo.  Search it. */
2185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      j = ML_(search_one_cfitab)( di, ip );
2186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(j >= -1 && j < (Word)di->cfsi_used);
2187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (j != -1) {
2189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         i = j;
2190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break; /* found it */
2191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (i == -1) {
2195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* we didn't find it. */
2197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *diP = (DebugInfo*)1;
2198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *ixP = 0;
2199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* found it. */
2203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ensure that di is 4-aligned (at least), so it can't possibly
2204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         be equal to (DebugInfo*)1. */
2205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(di && VG_IS_4_ALIGNED(di));
2206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(i >= 0 && i < di->cfsi_used);
2207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *diP = di;
2208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *ixP = i;
2209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Start of performance-enhancing hack: once every 64 (chosen
2211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         hackily after profiling) successful searches, move the found
2212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DebugInfo one step closer to the start of the list.  This
2213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         makes future searches cheaper.  For starting konqueror on
2214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         amd64, this in fact reduces the total amount of searching
2215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         done by the above find-the-right-DebugInfo loop by more than
2216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         a factor of 20. */
2217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ((n_search & 0xF) == 0) {
2218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Move di one step closer to the start of the list. */
2219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         move_DebugInfo_one_step_forward( di );
2220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* End of performance-enhancing hack. */
2222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0 && ((n_search & 0x7FFFF) == 0))
2224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("find_DiCfSI: %lu searches, "
2225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     "%lu DebugInfos looked at\n",
2226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     n_search, n_steps);
2227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Now follows a mechanism for caching queries to find_DiCfSI, since
2234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   they are extremely frequent on amd64-linux, during stack unwinding.
2235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Each cache entry binds an ip value to a (di, ix) pair.  Possible
2237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   values:
2238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   di is non-null, ix >= 0  ==>  cache slot in use, "di->cfsi[ix]"
2240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   di is (DebugInfo*)1      ==>  cache slot in use, no associated di
2241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   di is NULL               ==>  cache slot not in use
2242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Hence simply zeroing out the entire cache invalidates all
2244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   entries.
2245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Why not map ip values directly to DiCfSI*'s?  Because this would
2247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cause problems if/when the cfsi array is moved due to resizing.
2248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Instead we cache .cfsi array index value, which should be invariant
2249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   across resizing.  (That said, I don't think the current
2250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   implementation will resize whilst during queries, since the DiCfSI
2251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   records are added all at once, when the debuginfo for an object is
2252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   read, and is not changed ever thereafter. */
2253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2254436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov// Prime number, giving about 3K cache on 32 bits, 6K cache on 64 bits.
2255436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define N_CFSI_CACHE 509
2256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
2258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct { Addr ip; DebugInfo* di; Word ix; }
2259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CFSICacheEnt;
2260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic CFSICacheEnt cfsi_cache[N_CFSI_CACHE];
2262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void cfsi_cache__invalidate ( void ) {
2264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(&cfsi_cache, 0, sizeof(cfsi_cache));
2265436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   CF_info_generation++;
2266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2268436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovUInt VG_(CF_info_generation) (void)
2269436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
2270436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return CF_info_generation;
2271436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
2272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic inline CFSICacheEnt* cfsi_cache__find ( Addr ip )
2274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord         hash = ip % N_CFSI_CACHE;
2276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CFSICacheEnt* ce = &cfsi_cache[hash];
2277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static UWord  n_q = 0, n_m = 0;
2278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_q++;
2280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 && 0 == (n_q & 0x1FFFFF))
2281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("QQQ %lu %lu\n", n_q, n_m);
2282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (LIKELY(ce->ip == ip) && LIKELY(ce->di != NULL)) {
2284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* found an entry in the cache .. */
2285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* not found in cache.  Search and update. */
2287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_m++;
2288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ce->ip = ip;
2289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      find_DiCfSI( &ce->di, &ce->ix, ip );
2290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (UNLIKELY(ce->di == (DebugInfo*)1)) {
2293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* no DiCfSI for this address */
2294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
2295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* found a DiCfSI for this address */
2297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return ce;
2298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browninline
2303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Addr compute_cfa ( D3UnwindRegs* uregs,
2304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          Addr min_accessible, Addr max_accessible,
2305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          DebugInfo* di, DiCfSI* cfsi )
2306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CfiExprEvalContext eec;
2308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr               cfa;
2309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool               ok;
2310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Compute the CFA. */
2312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cfa = 0;
2313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (cfsi->cfa_how) {
2314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     if defined(VGA_x86) || defined(VGA_amd64)
2315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case CFIC_IA_SPREL:
2316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         cfa = cfsi->cfa_off + uregs->xsp;
2317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case CFIC_IA_BPREL:
2319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         cfa = cfsi->cfa_off + uregs->xbp;
2320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     elif defined(VGA_arm)
2322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case CFIC_ARM_R13REL:
2323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         cfa = cfsi->cfa_off + uregs->r13;
2324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case CFIC_ARM_R12REL:
2326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         cfa = cfsi->cfa_off + uregs->r12;
2327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case CFIC_ARM_R11REL:
2329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         cfa = cfsi->cfa_off + uregs->r11;
2330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case CFIC_ARM_R7REL:
2332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         cfa = cfsi->cfa_off + uregs->r7;
2333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2334b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#     elif defined(VGA_s390x)
2335b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case CFIC_IA_SPREL:
2336b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         cfa = cfsi->cfa_off + uregs->sp;
2337b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         break;
2338b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case CFIR_MEMCFAREL:
2339b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      {
2340b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         Addr a = uregs->sp + cfsi->cfa_off;
2341b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (a < min_accessible || a > max_accessible-sizeof(Addr))
2342b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            break;
2343b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         cfa = ML_(read_Addr)((void *)a);
2344b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         break;
2345b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
2346b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case CFIR_SAME:
2347b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         cfa = uregs->fp;
2348b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         break;
2349b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case CFIC_IA_BPREL:
2350b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         cfa = cfsi->cfa_off + uregs->fp;
2351b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         break;
2352436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#     elif defined(VGA_mips32) || defined(VGA_mips64)
2353663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      case CFIC_IA_SPREL:
2354663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         cfa = cfsi->cfa_off + uregs->sp;
2355663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         break;
2356663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      case CFIR_SAME:
2357663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         cfa = uregs->fp;
2358663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         break;
2359663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      case CFIC_IA_BPREL:
2360663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         cfa = cfsi->cfa_off + uregs->fp;
2361663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         break;
2362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     elif defined(VGA_ppc32) || defined(VGA_ppc64)
2363436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#     elif defined(VGP_arm64_linux)
2364436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case CFIC_ARM64_SPREL:
2365436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         cfa = cfsi->cfa_off + uregs->sp;
2366436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         break;
2367436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      case CFIC_ARM64_X29REL:
2368436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         cfa = cfsi->cfa_off + uregs->x29;
2369436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         break;
2370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     else
2371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#       error "Unsupported arch"
2372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     endif
2373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case CFIC_EXPR: /* available on all archs */
2374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (0) {
2375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(printf)("CFIC_EXPR: ");
2376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ML_(ppCfiExpr)(di->cfsi_exprs, cfsi->cfa_off);
2377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(printf)("\n");
2378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         eec.uregs          = uregs;
2380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         eec.min_accessible = min_accessible;
2381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         eec.max_accessible = max_accessible;
2382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ok = True;
2383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         cfa = evalCfiExpr(di->cfsi_exprs, cfsi->cfa_off, &eec, &ok );
2384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!ok) return 0;
2385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
2387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(0);
2388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return cfa;
2390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get the call frame address (CFA) given an IP/SP/FP triple. */
2394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* NOTE: This function may rearrange the order of entries in the
2395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo list. */
2396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownAddr ML_(get_CFA) ( Addr ip, Addr sp, Addr fp,
2397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Addr min_accessible, Addr max_accessible )
2398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CFSICacheEnt* ce;
2400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo*    di;
2401b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   DiCfSI*       cfsi __attribute__((unused));
2402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ce = cfsi_cache__find(ip);
2404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (UNLIKELY(ce == NULL))
2406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 0; /* no info.  Nothing we can do. */
2407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   di = ce->di;
2409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cfsi = &di->cfsi[ ce->ix ];
2410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Temporary impedance-matching kludge so that this keeps working
2412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      on x86-linux and amd64-linux. */
2413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGA_x86) || defined(VGA_amd64)
2414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { D3UnwindRegs uregs;
2415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     uregs.xip = ip;
2416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     uregs.xsp = sp;
2417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     uregs.xbp = fp;
2418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     return compute_cfa(&uregs,
2419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        min_accessible,  max_accessible, di, cfsi);
2420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2421b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#elif defined(VGA_s390x)
2422b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   { D3UnwindRegs uregs;
2423b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     uregs.ia = ip;
2424b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     uregs.sp = sp;
2425b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     uregs.fp = fp;
2426b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     return compute_cfa(&uregs,
2427b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                        min_accessible,  max_accessible, di, cfsi);
2428b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
2429eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov#elif defined(VGA_mips32) || defined(VGA_mips64)
2430eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   { D3UnwindRegs uregs;
2431eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov     uregs.pc = ip;
2432eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov     uregs.sp = sp;
2433eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov     uregs.fp = fp;
2434eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov     return compute_cfa(&uregs,
2435eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                        min_accessible,  max_accessible, di, cfsi);
2436eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   }
2437b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
2438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
2439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 0; /* indicates failure */
2440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
2441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The main function for DWARF2/3 CFI-based stack unwinding.  Given a
2445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   set of registers in UREGS, modify it to hold the register values
2446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for the previous frame, if possible.  Returns True if successful.
2447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If not successful, *UREGS is not changed.
2448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   For x86 and amd64, the unwound registers are: {E,R}IP,
2450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {E,R}SP, {E,R}BP.
2451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   For arm, the unwound registers are: R7 R11 R12 R13 R14 R15.
2453436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
2454436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   For arm64, the unwound registers are: X29(FP) X30(LR) SP PC.
2455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(use_CF_info) ( /*MOD*/D3UnwindRegs* uregsHere,
2457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        Addr min_accessible,
2458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        Addr max_accessible )
2459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo*         di;
2461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DiCfSI*            cfsi = NULL;
2462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr               cfa, ipHere = 0;
2463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CFSICacheEnt*      ce;
2464b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   CfiExprEvalContext eec __attribute__((unused));
2465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   D3UnwindRegs       uregsPrev;
2466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGA_x86) || defined(VGA_amd64)
2468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ipHere = uregsHere->xip;
2469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGA_arm)
2470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ipHere = uregsHere->r15;
2471b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  elif defined(VGA_s390x)
2472b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   ipHere = uregsHere->ia;
2473436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  elif defined(VGA_mips32) || defined(VGA_mips64)
2474663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   ipHere = uregsHere->pc;
2475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGA_ppc32) || defined(VGA_ppc64)
2476436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  elif defined(VGP_arm64_linux)
2477436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ipHere = uregsHere->pc;
2478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
2479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown arch"
2480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
2481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ce = cfsi_cache__find(ipHere);
2482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (UNLIKELY(ce == NULL))
2484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False; /* no info.  Nothing we can do. */
2485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   di = ce->di;
2487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cfsi = &di->cfsi[ ce->ix ];
2488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) {
2490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("found cfisi: ");
2491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ML_(ppDiCfSI)(di->cfsi_exprs, cfsi);
2492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(bzero_inline)(&uregsPrev, sizeof(uregsPrev));
2495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First compute the CFA. */
2497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cfa = compute_cfa(uregsHere,
2498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     min_accessible, max_accessible, di, cfsi);
2499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (UNLIKELY(cfa == 0))
2500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
2501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Now we know the CFA, use it to roll back the registers we're
2503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      interested in. */
2504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define COMPUTE(_prev, _here, _how, _off)             \
2506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do {                                              \
2507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (_how) {                                \
2508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case CFIR_UNKNOWN:                          \
2509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;                            \
2510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case CFIR_SAME:                             \
2511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               _prev = _here; break;                    \
2512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case CFIR_MEMCFAREL: {                      \
2513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Addr a = cfa + (Word)_off;               \
2514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (a < min_accessible                   \
2515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   || a > max_accessible-sizeof(Addr))  \
2516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return False;                         \
2517b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               _prev = ML_(read_Addr)((void *)a);       \
2518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;                                   \
2519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }                                           \
2520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case CFIR_CFAREL:                           \
2521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               _prev = cfa + (Word)_off;                \
2522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;                                   \
2523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case CFIR_EXPR:                             \
2524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (0)                                   \
2525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  ML_(ppCfiExpr)(di->cfsi_exprs,_off);  \
2526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               eec.uregs = uregsHere;                   \
2527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               eec.min_accessible = min_accessible;     \
2528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               eec.max_accessible = max_accessible;     \
2529b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               Bool ok = True;                          \
2530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               _prev = evalCfiExpr(di->cfsi_exprs, _off, &eec, &ok ); \
2531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (!ok) return False;                   \
2532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;                                   \
2533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:                                    \
2534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vg_assert(0);                            \
2535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }                                              \
2536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } while (0)
2537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGA_x86) || defined(VGA_amd64)
2539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   COMPUTE(uregsPrev.xip, uregsHere->xip, cfsi->ra_how, cfsi->ra_off);
2540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   COMPUTE(uregsPrev.xsp, uregsHere->xsp, cfsi->sp_how, cfsi->sp_off);
2541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   COMPUTE(uregsPrev.xbp, uregsHere->xbp, cfsi->bp_how, cfsi->bp_off);
2542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGA_arm)
2543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   COMPUTE(uregsPrev.r15, uregsHere->r15, cfsi->ra_how,  cfsi->ra_off);
2544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   COMPUTE(uregsPrev.r14, uregsHere->r14, cfsi->r14_how, cfsi->r14_off);
2545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   COMPUTE(uregsPrev.r13, uregsHere->r13, cfsi->r13_how, cfsi->r13_off);
2546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   COMPUTE(uregsPrev.r12, uregsHere->r12, cfsi->r12_how, cfsi->r12_off);
2547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   COMPUTE(uregsPrev.r11, uregsHere->r11, cfsi->r11_how, cfsi->r11_off);
2548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   COMPUTE(uregsPrev.r7,  uregsHere->r7,  cfsi->r7_how,  cfsi->r7_off);
2549b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  elif defined(VGA_s390x)
2550b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   COMPUTE(uregsPrev.ia, uregsHere->ia, cfsi->ra_how, cfsi->ra_off);
2551b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   COMPUTE(uregsPrev.sp, uregsHere->sp, cfsi->sp_how, cfsi->sp_off);
2552b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   COMPUTE(uregsPrev.fp, uregsHere->fp, cfsi->fp_how, cfsi->fp_off);
2553436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  elif defined(VGA_mips32) || defined(VGA_mips64)
2554663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   COMPUTE(uregsPrev.pc, uregsHere->pc, cfsi->ra_how, cfsi->ra_off);
2555663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   COMPUTE(uregsPrev.sp, uregsHere->sp, cfsi->sp_how, cfsi->sp_off);
2556663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   COMPUTE(uregsPrev.fp, uregsHere->fp, cfsi->fp_how, cfsi->fp_off);
2557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGA_ppc32) || defined(VGA_ppc64)
2558436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  elif defined(VGP_arm64_linux)
2559436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   COMPUTE(uregsPrev.pc,  uregsHere->pc,  cfsi->ra_how,  cfsi->ra_off);
2560436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   COMPUTE(uregsPrev.sp,  uregsHere->sp,  cfsi->sp_how,  cfsi->sp_off);
2561436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   COMPUTE(uregsPrev.x30, uregsHere->x30, cfsi->x30_how, cfsi->x30_off);
2562436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   COMPUTE(uregsPrev.x29, uregsHere->x29, cfsi->x29_how, cfsi->x29_off);
2563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
2564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown arch"
2565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
2566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef COMPUTE
2568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *uregsHere = uregsPrev;
2570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
2571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------*/
2575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                        ---*/
2576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- TOP LEVEL: FOR UNWINDING THE STACK USING               ---*/
2577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---            MSVC FPO INFO                               ---*/
2578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                        ---*/
2579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------*/
2580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(use_FPO_info) ( /*MOD*/Addr* ipP,
2582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*MOD*/Addr* spP,
2583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /*MOD*/Addr* fpP,
2584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Addr min_accessible,
2585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Addr max_accessible )
2586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word       i;
2588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* di;
2589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FPO_DATA*  fpo = NULL;
2590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr       spHere;
2591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static UWord n_search = 0;
2593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static UWord n_steps = 0;
2594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_search++;
2595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) VG_(printf)("search FPO for %#lx\n", *ipP);
2597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (di = debugInfo_list; di != NULL; di = di->next) {
2599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_steps++;
2600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Use the per-DebugInfo summary address ranges to skip
2602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         inapplicable DebugInfos quickly. */
2603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di->fpo == NULL)
2604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
2605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (*ipP < di->fpo_minavma || *ipP > di->fpo_maxavma)
2606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
2607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      i = ML_(search_one_fpotab)( di, *ipP );
2609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (i != -1) {
2610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Word j;
2611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (0) {
2612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* debug printing only */
2613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(printf)("look for %#lx  size %ld i %ld\n",
2614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        *ipP, di->fpo_size, i);
2615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for (j = 0; j < di->fpo_size; j++)
2616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               VG_(printf)("[%02ld] %#x %d\n",
2617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            j, di->fpo[j].ulOffStart, di->fpo[j].cbProcSize);
2618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(i >= 0 && i < di->fpo_size);
2620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         fpo = &di->fpo[i];
2621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
2622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (fpo == NULL)
2626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
2627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 && ((n_search & 0x7FFFF) == 0))
2629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("VG_(use_FPO_info): %lu searches, "
2630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "%lu DebugInfos looked at\n",
2631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  n_search, n_steps);
2632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Start of performance-enhancing hack: once every 64 (chosen
2635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hackily after profiling) successful searches, move the found
2636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DebugInfo one step closer to the start of the list.  This makes
2637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      future searches cheaper.  For starting konqueror on amd64, this
2638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      in fact reduces the total amount of searching done by the above
2639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      find-the-right-DebugInfo loop by more than a factor of 20. */
2640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((n_search & 0x3F) == 0) {
2641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Move si one step closer to the start of the list. */
2642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //move_DebugInfo_one_step_forward( di );
2643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* End of performance-enhancing hack. */
2645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) {
2647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("found fpo: ");
2648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //ML_(ppFPO)(fpo);
2649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*
2652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Stack layout is:
2653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   %esp->
2654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      4*.cbRegs  {%edi, %esi, %ebp, %ebx}
2655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      4*.cdwLocals
2656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return_pc
2657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      4*.cdwParams
2658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   prior_%esp->
2659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Typical code looks like:
2661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sub $4*.cdwLocals,%esp
2662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Alternative to above for >=4KB (and sometimes for smaller):
2663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mov $size,%eax
2664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            call __chkstk  # WinNT performs page-by-page probe!
2665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               __chkstk is much like alloc(), except that on return
2666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               %eax= 5+ &CALL.  Thus it could be used as part of
2667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Position Independent Code to locate the Global Offset Table.
2668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      push %ebx
2669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      push %ebp
2670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      push %esi
2671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Other once-only instructions often scheduled >here<.
2672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      push %edi
2673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If the pc is within the first .cbProlog bytes of the function,
2675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   then you must disassemble to see how many registers have been pushed,
2676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   because instructions in the prolog may be scheduled for performance.
2677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The order of PUSH is always %ebx, %ebp, %esi, %edi, with trailing
2678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   registers not pushed when .cbRegs < 4.  This seems somewhat strange
2679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   because %ebp is the register whose usage you want to minimize,
2680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   yet it is in the first half of the PUSH list.
2681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   I don't know what happens when the compiler constructs an outgoing CALL.
2683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   %esp could move if outgoing parameters are PUSHed, and this affects
2684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   traceback for errors during the PUSHes. */
2685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   spHere = *spP;
2687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2688b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   *ipP = ML_(read_Addr)((void *)(spHere + 4*(fpo->cbRegs + fpo->cdwLocals)));
2689b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   *spP =                         spHere + 4*(fpo->cbRegs + fpo->cdwLocals + 1
2690b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                                          + fpo->cdwParams);
2691b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   *fpP = ML_(read_Addr)((void *)(spHere + 4*2));
2692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
2693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------*/
2697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                        ---*/
2698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- TOP LEVEL: GENERATE DESCRIPTION OF DATA ADDRESSES      ---*/
2699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---            FROM DWARF3 DEBUG INFO                      ---*/
2700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                        ---*/
2701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------*/
2702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Try to make p2XA(dst, fmt, args..) turn into
2704b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(xaprintf)(dst, fmt, args) without having to resort to
2705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vararg macros.  As usual with everything to do with varargs, it's
2706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   an ugly hack.
2707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //#define p2XA(dstxa, format, args...)
2709b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   //   VG_(xaprintf)(dstxa, format, ##args)
2710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2711b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#define  p2XA  VG_(xaprintf)
2712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Add a zero-terminating byte to DST, which must be an XArray* of
2714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar. */
2715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void zterm_XA ( XArray* dst )
2716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar zero = 0;
2718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (void) VG_(addBytesToXA)( dst, &zero, 1 );
2719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Evaluate the location expression/list for var, to see whether or
2723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   not data_addr falls within the variable.  If so also return the
2724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   offset of data_addr from the start of the variable.  Note that
2725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   regs, which supplies ip,sp,fp values, will be NULL for global
2726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   variables, and non-NULL for local variables. */
2727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool data_address_is_in_var ( /*OUT*/PtrdiffT* offset,
2728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     XArray* /* TyEnt */ tyents,
2729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     DiVariable*   var,
2730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     RegSummary*   regs,
2731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     Addr          data_addr,
2732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     const DebugInfo* di )
2733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MaybeULong mul;
2735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SizeT      var_szB;
2736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   GXResult   res;
2737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool       show = False;
2738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(var->name);
2740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(var->gexpr);
2741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Figure out how big the variable is. */
2743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mul = ML_(sizeOfType)(tyents, var->typeR);
2744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If this var has a type whose size is unknown, zero, or
2745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      impossibly large, it should never have been added.  ML_(addVar)
2746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      should have rejected it. */
2747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(mul.b == True);
2748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(mul.ul > 0);
2749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sizeof(void*) == 4) vg_assert(mul.ul < (1ULL << 32));
2750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* After this point, we assume we can truncate mul.ul to a host word
2751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      safely (without loss of info). */
2752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   var_szB = (SizeT)mul.ul; /* NB: truncate to host word */
2754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (show) {
2756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("VVVV: data_address_%#lx_is_in_var: %s :: ",
2757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  data_addr, var->name );
2758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ML_(pp_TyEnt_C_ishly)( tyents, var->typeR );
2759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("\n");
2760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ignore zero-sized vars; they can never match anything. */
2763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (var_szB == 0) {
2764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (show)
2765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("VVVV: -> Fail (variable is zero sized)\n");
2766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
2767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = ML_(evaluate_GX)( var->gexpr, var->fbGX, regs, di );
2770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (show) {
2772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("VVVV: -> ");
2773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ML_(pp_GXResult)( res );
2774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("\n");
2775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (res.kind == GXR_Addr
2778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && res.word <= data_addr
2779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && data_addr < res.word + var_szB) {
2780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *offset = data_addr - res.word;
2781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
2782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
2784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Format the acquired information into DN(AME)1 and DN(AME)2, which
2789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   are XArray*s of HChar, that have been initialised by the caller.
2790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Resulting strings will be zero terminated.  Information is
2791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   formatted in an understandable way.  Not so easy.  If frameNo is
2792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   -1, this is assumed to be a global variable; else a local
2793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   variable. */
2794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void format_message ( /*MOD*/XArray* /* of HChar */ dn1,
2795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             /*MOD*/XArray* /* of HChar */ dn2,
2796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             Addr     data_addr,
2797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             DiVariable* var,
2798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             PtrdiffT var_offset,
2799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             PtrdiffT residual_offset,
2800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             XArray* /*UChar*/ described,
2801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             Int      frameNo,
2802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             ThreadId tid )
2803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   have_descr, have_srcloc;
2805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   xml       = VG_(clo_xml);
2806436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   const HChar* vo_plural = var_offset == 1 ? "" : "s";
2807436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   const HChar* ro_plural = residual_offset == 1 ? "" : "s";
2808436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   const HChar* basetag   = "auxwhat"; /* a constant */
2809436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   HChar tagL[32], tagR[32], xagL[32], xagR[32];
2810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2811b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (frameNo < -1) {
2812b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      vg_assert(0); /* Not allowed */
2813b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
2814b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   else if (frameNo == -1) {
2815b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      vg_assert(tid == VG_INVALID_THREADID);
2816b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
2817b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   else /* (frameNo >= 0) */ {
2818b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      vg_assert(tid != VG_INVALID_THREADID);
2819b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
2820b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
2821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(dn1 && dn2);
2822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(described);
2823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(var && var->name);
2824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   have_descr = VG_(sizeXA)(described) > 0
2825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                && *(UChar*)VG_(indexXA)(described,0) != '\0';
2826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   have_srcloc = var->fileName && var->lineNo > 0;
2827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tagL[0] = tagR[0] = xagL[0] = xagR[0] = 0;
2829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (xml) {
2830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(sprintf)(tagL, "<%s>",   basetag); // <auxwhat>
2831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(sprintf)(tagR, "</%s>",  basetag); // </auxwhat>
2832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(sprintf)(xagL, "<x%s>",  basetag); // <xauxwhat>
2833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(sprintf)(xagR, "</x%s>", basetag); // </xauxwhat>
2834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define TAGL(_xa) p2XA(_xa, "%s", tagL)
2837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define TAGR(_xa) p2XA(_xa, "%s", tagR)
2838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define XAGL(_xa) p2XA(_xa, "%s", xagL)
2839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define XAGR(_xa) p2XA(_xa, "%s", xagR)
2840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define TXTL(_xa) p2XA(_xa, "%s", "<text>")
2841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define TXTR(_xa) p2XA(_xa, "%s", "</text>")
2842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------ local cases ------ */
2844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( frameNo >= 0 && (!have_srcloc) && (!have_descr) ) {
2846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* no srcloc, no description:
2847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Location 0x7fefff6cf is 543 bytes inside local var "a",
2848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         in frame #1 of thread 1
2849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
2850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (xml) {
2851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGL( dn1 );
2852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn1,
2853b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "Location 0x%lx is %lu byte%s inside local var \"%pS\",",
2854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               data_addr, var_offset, vo_plural, var->name );
2855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGR( dn1 );
2856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGL( dn2 );
2857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn2,
2858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "in frame #%d of thread %d", frameNo, (Int)tid );
2859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGR( dn2 );
2860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn1,
2862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "Location 0x%lx is %lu byte%s inside local var \"%s\",",
2863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               data_addr, var_offset, vo_plural, var->name );
2864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn2,
2865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "in frame #%d of thread %d", frameNo, (Int)tid );
2866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( frameNo >= 0 && have_srcloc && (!have_descr) ) {
2870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* no description:
2871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Location 0x7fefff6cf is 543 bytes inside local var "a"
2872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         declared at dsyms7.c:17, in frame #1 of thread 1
2873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
2874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (xml) {
2875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGL( dn1 );
2876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn1,
2877b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "Location 0x%lx is %lu byte%s inside local var \"%pS\"",
2878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               data_addr, var_offset, vo_plural, var->name );
2879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGR( dn1 );
2880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         XAGL( dn2 );
2881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TXTL( dn2 );
2882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn2,
2883b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "declared at %pS:%d, in frame #%d of thread %d",
2884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               var->fileName, var->lineNo, frameNo, (Int)tid );
2885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TXTR( dn2 );
2886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FIXME: also do <dir>
2887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn2,
2888b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               " <file>%pS</file> <line>%d</line> ",
2889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               var->fileName, var->lineNo );
2890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         XAGR( dn2 );
2891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn1,
2893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "Location 0x%lx is %lu byte%s inside local var \"%s\"",
2894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               data_addr, var_offset, vo_plural, var->name );
2895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn2,
2896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "declared at %s:%d, in frame #%d of thread %d",
2897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               var->fileName, var->lineNo, frameNo, (Int)tid );
2898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( frameNo >= 0 && (!have_srcloc) && have_descr ) {
2902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* no srcloc:
2903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Location 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2
2904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         in frame #1 of thread 1
2905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
2906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (xml) {
2907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGL( dn1 );
2908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn1,
2909b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "Location 0x%lx is %lu byte%s inside %pS%pS",
2910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               data_addr, residual_offset, ro_plural, var->name,
2911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (HChar*)(VG_(indexXA)(described,0)) );
2912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGR( dn1 );
2913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGL( dn2 );
2914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn2,
2915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "in frame #%d of thread %d", frameNo, (Int)tid );
2916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGR( dn2 );
2917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn1,
2919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "Location 0x%lx is %lu byte%s inside %s%s",
2920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               data_addr, residual_offset, ro_plural, var->name,
2921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (HChar*)(VG_(indexXA)(described,0)) );
2922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn2,
2923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "in frame #%d of thread %d", frameNo, (Int)tid );
2924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( frameNo >= 0 && have_srcloc && have_descr ) {
2928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Location 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
2929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         declared at dsyms7.c:17, in frame #1 of thread 1 */
2930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (xml) {
2931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGL( dn1 );
2932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn1,
2933b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "Location 0x%lx is %lu byte%s inside %pS%pS,",
2934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               data_addr, residual_offset, ro_plural, var->name,
2935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (HChar*)(VG_(indexXA)(described,0)) );
2936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGR( dn1 );
2937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         XAGL( dn2 );
2938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TXTL( dn2 );
2939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn2,
2940b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "declared at %pS:%d, in frame #%d of thread %d",
2941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               var->fileName, var->lineNo, frameNo, (Int)tid );
2942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TXTR( dn2 );
2943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FIXME: also do <dir>
2944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn2,
2945b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               " <file>%pS</file> <line>%d</line> ",
2946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               var->fileName, var->lineNo );
2947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         XAGR( dn2 );
2948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn1,
2950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "Location 0x%lx is %lu byte%s inside %s%s,",
2951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               data_addr, residual_offset, ro_plural, var->name,
2952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (HChar*)(VG_(indexXA)(described,0)) );
2953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn2,
2954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "declared at %s:%d, in frame #%d of thread %d",
2955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               var->fileName, var->lineNo, frameNo, (Int)tid );
2956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------ global cases ------ */
2960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( frameNo >= -1 && (!have_srcloc) && (!have_descr) ) {
2961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* no srcloc, no description:
2962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Location 0x7fefff6cf is 543 bytes inside global var "a"
2963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
2964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (xml) {
2965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGL( dn1 );
2966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn1,
2967b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "Location 0x%lx is %lu byte%s inside global var \"%pS\"",
2968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               data_addr, var_offset, vo_plural, var->name );
2969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGR( dn1 );
2970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn1,
2972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "Location 0x%lx is %lu byte%s inside global var \"%s\"",
2973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               data_addr, var_offset, vo_plural, var->name );
2974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( frameNo >= -1 && have_srcloc && (!have_descr) ) {
2978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* no description:
2979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Location 0x7fefff6cf is 543 bytes inside global var "a"
2980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         declared at dsyms7.c:17
2981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
2982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (xml) {
2983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGL( dn1 );
2984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn1,
2985b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "Location 0x%lx is %lu byte%s inside global var \"%pS\"",
2986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               data_addr, var_offset, vo_plural, var->name );
2987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGR( dn1 );
2988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         XAGL( dn2 );
2989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TXTL( dn2 );
2990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn2,
2991b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "declared at %pS:%d",
2992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               var->fileName, var->lineNo);
2993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TXTR( dn2 );
2994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FIXME: also do <dir>
2995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn2,
2996b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               " <file>%pS</file> <line>%d</line> ",
2997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               var->fileName, var->lineNo );
2998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         XAGR( dn2 );
2999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
3000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn1,
3001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "Location 0x%lx is %lu byte%s inside global var \"%s\"",
3002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               data_addr, var_offset, vo_plural, var->name );
3003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn2,
3004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "declared at %s:%d",
3005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               var->fileName, var->lineNo);
3006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
3009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( frameNo >= -1 && (!have_srcloc) && have_descr ) {
3010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* no srcloc:
3011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Location 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
3012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         a global variable
3013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
3014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (xml) {
3015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGL( dn1 );
3016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn1,
3017b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "Location 0x%lx is %lu byte%s inside %pS%pS,",
3018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               data_addr, residual_offset, ro_plural, var->name,
3019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (HChar*)(VG_(indexXA)(described,0)) );
3020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGR( dn1 );
3021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGL( dn2 );
3022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn2,
3023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "a global variable");
3024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGR( dn2 );
3025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
3026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn1,
3027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "Location 0x%lx is %lu byte%s inside %s%s,",
3028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               data_addr, residual_offset, ro_plural, var->name,
3029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (char*)(VG_(indexXA)(described,0)) );
3030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn2,
3031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "a global variable");
3032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
3035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( frameNo >= -1 && have_srcloc && have_descr ) {
3036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Location 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
3037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         a global variable declared at dsyms7.c:17 */
3038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (xml) {
3039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGL( dn1 );
3040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn1,
3041b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "Location 0x%lx is %lu byte%s inside %pS%pS,",
3042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               data_addr, residual_offset, ro_plural, var->name,
3043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (HChar*)(VG_(indexXA)(described,0)) );
3044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TAGR( dn1 );
3045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         XAGL( dn2 );
3046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TXTL( dn2 );
3047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn2,
3048b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "a global variable declared at %pS:%d",
3049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               var->fileName, var->lineNo);
3050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         TXTR( dn2 );
3051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // FIXME: also do <dir>
3052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn2,
3053b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               " <file>%pS</file> <line>%d</line> ",
3054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               var->fileName, var->lineNo );
3055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         XAGR( dn2 );
3056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
3057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn1,
3058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "Location 0x%lx is %lu byte%s inside %s%s,",
3059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               data_addr, residual_offset, ro_plural, var->name,
3060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (HChar*)(VG_(indexXA)(described,0)) );
3061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         p2XA( dn2,
3062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "a global variable declared at %s:%d",
3063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               var->fileName, var->lineNo);
3064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
3067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(0);
3068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Zero terminate both strings */
3070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   zterm_XA( dn1 );
3071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   zterm_XA( dn2 );
3072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef TAGL
3074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef TAGR
3075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef XAGL
3076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef XAGR
3077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef TXTL
3078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef TXTR
3079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Determine if data_addr is a local variable in the frame
3083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   characterised by (ip,sp,fp), and if so write its description at the
3084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ends of DNAME{1,2}, which are XArray*s of HChar, that have been
3085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   initialised by the caller, zero terminate both, and return True.
3086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If it's not a local variable in said frame, return False. */
3087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool consider_vars_in_frame ( /*MOD*/XArray* /* of HChar */ dname1,
3089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              /*MOD*/XArray* /* of HChar */ dname2,
3090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              Addr data_addr,
3091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              Addr ip, Addr sp, Addr fp,
3092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              /* shown to user: */
3093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              ThreadId tid, Int frameNo )
3094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word       i;
3096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* di;
3097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   RegSummary regs;
3098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool debug = False;
3099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static UInt n_search = 0;
3101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static UInt n_steps = 0;
3102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_search++;
3103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (debug)
3104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("QQQQ: cvif: ip,sp,fp %#lx,%#lx,%#lx\n", ip,sp,fp);
3105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* first, find the DebugInfo that pertains to 'ip'. */
3106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (di = debugInfo_list; di; di = di->next) {
3107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_steps++;
3108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* text segment missing? unlikely, but handle it .. */
3109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!di->text_present || di->text_size == 0)
3110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
3111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Ok.  So does this text mapping bracket the ip? */
3112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di->text_avma <= ip && ip < di->text_avma + di->text_size)
3113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Didn't find it.  Strange -- means ip is a code address outside
3117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      of any mapped text segment.  Unlikely but not impossible -- app
3118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      could be generating code to run. */
3119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!di)
3120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
3121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 && ((n_search & 0x1) == 0))
3123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("consider_vars_in_frame: %u searches, "
3124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "%u DebugInfos looked at\n",
3125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  n_search, n_steps);
3126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Start of performance-enhancing hack: once every ??? (chosen
3127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hackily after profiling) successful searches, move the found
3128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DebugInfo one step closer to the start of the list.  This makes
3129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      future searches cheaper. */
3130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((n_search & 0xFFFF) == 0) {
3131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Move si one step closer to the start of the list. */
3132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      move_DebugInfo_one_step_forward( di );
3133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* End of performance-enhancing hack. */
3135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* any var info at all? */
3137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!di->varinfo)
3138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
3139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Work through the scopes from most deeply nested outwards,
3141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      looking for code address ranges that bracket 'ip'.  The
3142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      variables on each such address range found are in scope right
3143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      now.  Don't descend to level zero as that is the global
3144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      scope. */
3145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   regs.ip = ip;
3146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   regs.sp = sp;
3147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   regs.fp = fp;
3148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* "for each scope, working outwards ..." */
3150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = VG_(sizeXA)(di->varinfo) - 1; i >= 1; i--) {
3151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XArray*      vars;
3152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Word         j;
3153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DiAddrRange* arange;
3154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      OSet*        this_scope
3155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = *(OSet**)VG_(indexXA)( di->varinfo, i );
3156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (debug)
3157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("QQQQ:   considering scope %ld\n", (Word)i);
3158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!this_scope)
3159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
3160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Find the set of variables in this scope that
3161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         bracket the program counter. */
3162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arange = VG_(OSetGen_LookupWithCmp)(
3163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  this_scope, &ip,
3164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  ML_(cmp_for_DiAddrRange_range)
3165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
3166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!arange)
3167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
3168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* stay sane */
3169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(arange->aMin <= arange->aMax);
3170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* It must bracket the ip we asked for, else
3171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ML_(cmp_for_DiAddrRange_range) is somehow broken. */
3172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(arange->aMin <= ip && ip <= arange->aMax);
3173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* It must have an attached XArray of DiVariables. */
3174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vars = arange->vars;
3175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(vars);
3176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* But it mustn't cover the entire address range.  We only
3177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         expect that to happen for the global scope (level 0), which
3178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         we're not looking at here.  Except, it may cover the entire
3179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         address range, but in that case the vars array must be
3180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         empty. */
3181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(! (arange->aMin == (Addr)0
3182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   && arange->aMax == ~(Addr)0
3183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   && VG_(sizeXA)(vars) > 0) );
3184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (j = 0; j < VG_(sizeXA)( vars ); j++) {
3185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DiVariable* var = (DiVariable*)VG_(indexXA)( vars, j );
3186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         PtrdiffT    offset;
3187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (debug)
3188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(printf)("QQQQ:    var:name=%s %#lx-%#lx %#lx\n",
3189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        var->name,arange->aMin,arange->aMax,ip);
3190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (data_address_is_in_var( &offset, di->admin_tyents,
3191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     var, &regs,
3192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     data_addr, di )) {
3193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            PtrdiffT residual_offset = 0;
3194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            XArray* described = ML_(describe_type)( &residual_offset,
3195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                    di->admin_tyents,
3196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                    var->typeR, offset );
3197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            format_message( dname1, dname2,
3198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            data_addr, var, offset, residual_offset,
3199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            described, frameNo, tid );
3200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(deleteXA)( described );
3201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
3202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
3203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
3207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Try to form some description of DATA_ADDR by looking at the DWARF3
3210436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   debug info we have.  This considers all global variables, and 8
3211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   frames in the stacks of all threads.  Result is written at the ends
3212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of DNAME{1,2}V, which are XArray*s of HChar, that have been
3213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   initialised by the caller, and True is returned.  If no description
3214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is created, False is returned.  Regardless of the return value,
3215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DNAME{1,2}V are guaranteed to be zero terminated after the call.
3216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Note that after the call, DNAME{1,2} may have more than one
3218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   trailing zero, so callers should establish the useful text length
3219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   using VG_(strlen) on the contents, rather than VG_(sizeXA) on the
3220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XArray itself.
3221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(get_data_description)(
3223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /*MOD*/ void* /* really, XArray* of HChar */ dname1v,
3224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /*MOD*/ void* /* really, XArray* of HChar */ dname2v,
3225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        Addr data_addr
3226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     )
3227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define N_FRAMES 8
3229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr ips[N_FRAMES], sps[N_FRAMES], fps[N_FRAMES];
3230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt n_frames;
3231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr       stack_min, stack_max;
3233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId   tid;
3234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool       found;
3235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* di;
3236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word       j;
3237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XArray*    dname1 = (XArray*)dname1v;
3239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XArray*    dname2 = (XArray*)dname2v;
3240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) VG_(printf)("get_data_description: dataaddr %#lx\n", data_addr);
3242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First, see if data_addr is (or is part of) a global variable.
3243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Loop over the DebugInfos we have.  Check data_addr against the
3244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      outermost scope of all of them, as that should be a global
3245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      scope. */
3246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (di = debugInfo_list; di != NULL; di = di->next) {
3247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      OSet*        global_scope;
3248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Word         gs_size;
3249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr         zero;
3250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DiAddrRange* global_arange;
3251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Word         i;
3252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XArray*      vars;
3253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* text segment missing? unlikely, but handle it .. */
3255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!di->text_present || di->text_size == 0)
3256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
3257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* any var info at all? */
3258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!di->varinfo)
3259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
3260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* perhaps this object didn't contribute any vars at all? */
3261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(sizeXA)( di->varinfo ) == 0)
3262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
3263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      global_scope = *(OSet**)VG_(indexXA)( di->varinfo, 0 );
3264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(global_scope);
3265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gs_size = VG_(OSetGen_Size)( global_scope );
3266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* The global scope might be completely empty if this
3267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         compilation unit declared locals but nothing global. */
3268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (gs_size == 0)
3269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          continue;
3270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* But if it isn't empty, then it must contain exactly one
3271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         element, which covers the entire address range. */
3272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(gs_size == 1);
3273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Fish out the global scope and check it is as expected. */
3274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      zero = 0;
3275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      global_arange
3276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = VG_(OSetGen_Lookup)( global_scope, &zero );
3277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* The global range from (Addr)0 to ~(Addr)0 must exist */
3278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(global_arange);
3279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(global_arange->aMin == (Addr)0
3280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                && global_arange->aMax == ~(Addr)0);
3281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Any vars in this range? */
3282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!global_arange->vars)
3283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
3284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Ok, there are some vars in the global scope of this
3285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DebugInfo.  Wade through them and see if the data addresses
3286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         of any of them bracket data_addr. */
3287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vars = global_arange->vars;
3288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < VG_(sizeXA)( vars ); i++) {
3289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         PtrdiffT offset;
3290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DiVariable* var = (DiVariable*)VG_(indexXA)( vars, i );
3291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(var->name);
3292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Note we use a NULL RegSummary* here.  It can't make any
3293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sense for a global variable to have a location expression
3294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            which depends on a SP/FP/IP value.  So don't supply any.
3295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            This means, if the evaluation of the location
3296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            expression/list requires a register, we have to let it
3297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fail. */
3298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (data_address_is_in_var( &offset, di->admin_tyents, var,
3299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     NULL/* RegSummary* */,
3300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     data_addr, di )) {
3301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            PtrdiffT residual_offset = 0;
3302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            XArray* described = ML_(describe_type)( &residual_offset,
3303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                    di->admin_tyents,
3304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                    var->typeR, offset );
3305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            format_message( dname1, dname2,
3306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            data_addr, var, offset, residual_offset,
3307b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                            described, -1/*frameNo*/,
3308b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                            VG_INVALID_THREADID );
3309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(deleteXA)( described );
3310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            zterm_XA( dname1 );
3311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            zterm_XA( dname2 );
3312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
3313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
3314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Ok, well it's not a global variable.  So now let's snoop around
3318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      in the stacks of all the threads.  First try to figure out which
3319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      thread's stack data_addr is in. */
3320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Perhaps it's on a thread's stack? */
3322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   found = False;
3323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(thread_stack_reset_iter)(&tid);
3324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) {
3325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (stack_min >= stack_max)
3326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue; /* ignore obviously stupid cases */
3327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (stack_min - VG_STACK_REDZONE_SZB <= data_addr
3328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && data_addr <= stack_max) {
3329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         found = True;
3330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!found) {
3334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      zterm_XA( dname1 );
3335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      zterm_XA( dname2 );
3336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
3337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We conclude data_addr is in thread tid's stack.  Unwind the
3340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stack to get a bunch of (ip,sp,fp) triples describing the
3341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      frames, and for each frame, consider the local variables. */
3342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_frames = VG_(get_StackTrace)( tid, ips, N_FRAMES,
3343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   sps, fps, 0/*first_ip_delta*/ );
3344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(n_frames >= 0 && n_frames <= N_FRAMES);
3346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (j = 0; j < n_frames; j++) {
3347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (consider_vars_in_frame( dname1, dname2,
3348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  data_addr,
3349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  ips[j],
3350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  sps[j], fps[j], tid, j )) {
3351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         zterm_XA( dname1 );
3352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         zterm_XA( dname2 );
3353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
3354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Now, it appears that gcc sometimes appears to produce
3356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         location lists whose ranges don't actually cover the call
3357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         instruction, even though the address of the variable in
3358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         question is passed as a parameter in the call.  AFAICS this
3359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         is simply a bug in gcc - how can the variable be claimed not
3360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         exist in memory (on the stack) for the duration of a call in
3361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         which its address is passed?  But anyway, in the particular
3362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case I investigated (memcheck/tests/varinfo6.c, call to croak
3363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         on line 2999, local var budget declared at line 3115
3364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         appearing not to exist across the call to mainSort on line
3365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         3143, "gcc.orig (GCC) 3.4.4 20050721 (Red Hat 3.4.4-2)" on
3366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         amd64), the variable's location list does claim it exists
3367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         starting at the first byte of the first instruction after the
3368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         call instruction.  So, call consider_vars_in_frame a second
3369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         time, but this time add 1 to the IP.  GDB handles this
3370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         example with no difficulty, which leads me to believe that
3371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         either (1) I misunderstood something, or (2) GDB has an
3372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         equivalent kludge. */
3373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (j > 0 /* this is a non-innermost frame */
3374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && consider_vars_in_frame( dname1, dname2,
3375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     data_addr,
3376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     ips[j] + 1,
3377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     sps[j], fps[j], tid, j )) {
3378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         zterm_XA( dname1 );
3379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         zterm_XA( dname2 );
3380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
3381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We didn't find anything useful. */
3385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   zterm_XA( dname1 );
3386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   zterm_XA( dname2 );
3387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
3388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef N_FRAMES
3389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//////////////////////////////////////////////////////////////////
3393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                                                              //
3394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Support for other kinds of queries to the Dwarf3 var info    //
3395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                                                              //
3396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//////////////////////////////////////////////////////////////////
3397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Figure out if the variable 'var' has a location that is linearly
3399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dependent on a stack pointer value, or a frame pointer value, and
3400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if it is, add a description of it to 'blocks'.  Otherwise ignore
3401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   it.  If 'arrays_only' is True, also ignore it unless it has an
3402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   array type. */
3403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid analyse_deps ( /*MOD*/XArray* /* of FrameBlock */ blocks,
3406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    XArray* /* TyEnt */ tyents,
3407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Addr ip, const DebugInfo* di, DiVariable* var,
3408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool arrays_only )
3409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   GXResult   res_sp_6k, res_sp_7k, res_fp_6k, res_fp_7k;
3411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   RegSummary regs;
3412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MaybeULong mul;
3413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool       isVec;
3414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TyEnt*     ty;
3415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool debug = False;
3417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0&&debug)
3418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("adeps: var %s\n", var->name );
3419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Figure out how big the variable is. */
3421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mul = ML_(sizeOfType)(tyents, var->typeR);
3422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If this var has a type whose size is unknown, zero, or
3423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      impossibly large, it should never have been added.  ML_(addVar)
3424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      should have rejected it. */
3425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(mul.b == True);
3426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(mul.ul > 0);
3427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sizeof(void*) == 4) vg_assert(mul.ul < (1ULL << 32));
3428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* After this point, we assume we can truncate mul.ul to a host word
3429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      safely (without loss of info). */
3430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* skip if non-array and we're only interested in arrays */
3432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ty = ML_(TyEnts__index_by_cuOff)( tyents, NULL, var->typeR );
3433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(ty);
3434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(ty->tag == Te_UNKNOWN || ML_(TyEnt__is_type)(ty));
3435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ty->tag == Te_UNKNOWN)
3436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return; /* perhaps we should complain in this case? */
3437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   isVec = ty->tag == Te_TyArray;
3438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (arrays_only && !isVec)
3439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
3440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) {ML_(pp_TyEnt_C_ishly)(tyents, var->typeR);
3442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           VG_(printf)("  %s\n", var->name);}
3443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Do some test evaluations of the variable's location expression,
3445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      in order to guess whether it is sp-relative, fp-relative, or
3446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      none.  A crude hack, which can be interpreted roughly as finding
3447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the first derivative of the location expression w.r.t. the
3448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      supplied frame and stack pointer values. */
3449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   regs.fp   = 0;
3450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   regs.ip   = ip;
3451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   regs.sp   = 6 * 1024;
3452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res_sp_6k = ML_(evaluate_GX)( var->gexpr, var->fbGX, &regs, di );
3453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   regs.fp   = 0;
3455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   regs.ip   = ip;
3456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   regs.sp   = 7 * 1024;
3457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res_sp_7k = ML_(evaluate_GX)( var->gexpr, var->fbGX, &regs, di );
3458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   regs.fp   = 6 * 1024;
3460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   regs.ip   = ip;
3461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   regs.sp   = 0;
3462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res_fp_6k = ML_(evaluate_GX)( var->gexpr, var->fbGX, &regs, di );
3463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   regs.fp   = 7 * 1024;
3465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   regs.ip   = ip;
3466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   regs.sp   = 0;
3467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res_fp_7k = ML_(evaluate_GX)( var->gexpr, var->fbGX, &regs, di );
3468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(res_sp_6k.kind == res_sp_7k.kind);
3470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(res_sp_6k.kind == res_fp_6k.kind);
3471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(res_sp_6k.kind == res_fp_7k.kind);
3472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (res_sp_6k.kind == GXR_Addr) {
3474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      StackBlock block;
3475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      GXResult res;
3476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UWord sp_delta = res_sp_7k.word - res_sp_6k.word;
3477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UWord fp_delta = res_fp_7k.word - res_fp_6k.word;
3478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(sp_delta == 0 || sp_delta == 1024);
3479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(fp_delta == 0 || fp_delta == 1024);
3480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sp_delta == 0 && fp_delta == 0) {
3482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* depends neither on sp nor fp, so it can't be a stack
3483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            local.  Ignore it. */
3484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
3486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sp_delta == 1024 && fp_delta == 0) {
3487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         regs.sp = regs.fp = 0;
3488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         regs.ip = ip;
3489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = ML_(evaluate_GX)( var->gexpr, var->fbGX, &regs, di );
3490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(res.kind == GXR_Addr);
3491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (debug)
3492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("   %5ld .. %5ld (sp) %s\n",
3493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     res.word, res.word + ((UWord)mul.ul) - 1, var->name);
3494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         block.base  = res.word;
3495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         block.szB   = (SizeT)mul.ul;
3496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         block.spRel = True;
3497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         block.isVec = isVec;
3498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(memset)( &block.name[0], 0, sizeof(block.name) );
3499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (var->name)
3500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(strncpy)( &block.name[0], var->name, sizeof(block.name)-1 );
3501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         block.name[ sizeof(block.name)-1 ] = 0;
3502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(addToXA)( blocks, &block );
3503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
3505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sp_delta == 0 && fp_delta == 1024) {
3506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         regs.sp = regs.fp = 0;
3507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         regs.ip = ip;
3508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = ML_(evaluate_GX)( var->gexpr, var->fbGX, &regs, di );
3509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(res.kind == GXR_Addr);
3510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (debug)
3511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("   %5ld .. %5ld (FP) %s\n",
3512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     res.word, res.word + ((UWord)mul.ul) - 1, var->name);
3513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         block.base  = res.word;
3514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         block.szB   = (SizeT)mul.ul;
3515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         block.spRel = False;
3516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         block.isVec = isVec;
3517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(memset)( &block.name[0], 0, sizeof(block.name) );
3518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (var->name)
3519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(strncpy)( &block.name[0], var->name, sizeof(block.name)-1 );
3520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         block.name[ sizeof(block.name)-1 ] = 0;
3521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(addToXA)( blocks, &block );
3522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else {
3524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(0);
3525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get an XArray of StackBlock which describe the stack (auto) blocks
3531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for this ip.  The caller is expected to free the XArray at some
3532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   point.  If 'arrays_only' is True, only array-typed blocks are
3533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   returned; otherwise blocks of all types are returned. */
3534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid* /* really, XArray* of StackBlock */
3536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(di_get_stack_blocks_at_ip)( Addr ip, Bool arrays_only )
3537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This is a derivation of consider_vars_in_frame() above. */
3539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word       i;
3540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* di;
3541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool debug = False;
3542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XArray* res = VG_(newXA)( ML_(dinfo_zalloc), "di.debuginfo.dgsbai.1",
3544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             ML_(dinfo_free),
3545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             sizeof(StackBlock) );
3546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static UInt n_search = 0;
3548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static UInt n_steps = 0;
3549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_search++;
3550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (debug)
3551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("QQQQ: dgsbai: ip %#lx\n", ip);
3552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* first, find the DebugInfo that pertains to 'ip'. */
3553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (di = debugInfo_list; di; di = di->next) {
3554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_steps++;
3555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* text segment missing? unlikely, but handle it .. */
3556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!di->text_present || di->text_size == 0)
3557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
3558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Ok.  So does this text mapping bracket the ip? */
3559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di->text_avma <= ip && ip < di->text_avma + di->text_size)
3560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Didn't find it.  Strange -- means ip is a code address outside
3564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      of any mapped text segment.  Unlikely but not impossible -- app
3565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      could be generating code to run. */
3566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!di)
3567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return res; /* currently empty */
3568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 && ((n_search & 0x1) == 0))
3570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("VG_(di_get_stack_blocks_at_ip): %u searches, "
3571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "%u DebugInfos looked at\n",
3572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  n_search, n_steps);
3573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Start of performance-enhancing hack: once every ??? (chosen
3574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hackily after profiling) successful searches, move the found
3575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DebugInfo one step closer to the start of the list.  This makes
3576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      future searches cheaper. */
3577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((n_search & 0xFFFF) == 0) {
3578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Move si one step closer to the start of the list. */
3579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      move_DebugInfo_one_step_forward( di );
3580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* End of performance-enhancing hack. */
3582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* any var info at all? */
3584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!di->varinfo)
3585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return res; /* currently empty */
3586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Work through the scopes from most deeply nested outwards,
3588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      looking for code address ranges that bracket 'ip'.  The
3589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      variables on each such address range found are in scope right
3590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      now.  Don't descend to level zero as that is the global
3591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      scope. */
3592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* "for each scope, working outwards ..." */
3594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = VG_(sizeXA)(di->varinfo) - 1; i >= 1; i--) {
3595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XArray*      vars;
3596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Word         j;
3597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DiAddrRange* arange;
3598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      OSet*        this_scope
3599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = *(OSet**)VG_(indexXA)( di->varinfo, i );
3600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (debug)
3601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("QQQQ:   considering scope %ld\n", (Word)i);
3602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!this_scope)
3603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
3604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Find the set of variables in this scope that
3605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         bracket the program counter. */
3606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arange = VG_(OSetGen_LookupWithCmp)(
3607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  this_scope, &ip,
3608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  ML_(cmp_for_DiAddrRange_range)
3609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
3610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!arange)
3611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
3612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* stay sane */
3613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(arange->aMin <= arange->aMax);
3614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* It must bracket the ip we asked for, else
3615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ML_(cmp_for_DiAddrRange_range) is somehow broken. */
3616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(arange->aMin <= ip && ip <= arange->aMax);
3617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* It must have an attached XArray of DiVariables. */
3618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vars = arange->vars;
3619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(vars);
3620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* But it mustn't cover the entire address range.  We only
3621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         expect that to happen for the global scope (level 0), which
3622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         we're not looking at here.  Except, it may cover the entire
3623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         address range, but in that case the vars array must be
3624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         empty. */
3625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(! (arange->aMin == (Addr)0
3626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   && arange->aMax == ~(Addr)0
3627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   && VG_(sizeXA)(vars) > 0) );
3628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (j = 0; j < VG_(sizeXA)( vars ); j++) {
3629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DiVariable* var = (DiVariable*)VG_(indexXA)( vars, j );
3630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (debug)
3631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(printf)("QQQQ:    var:name=%s %#lx-%#lx %#lx\n",
3632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        var->name,arange->aMin,arange->aMax,ip);
3633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         analyse_deps( res, di->admin_tyents, ip,
3634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       di, var, arrays_only );
3635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res;
3639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get an array of GlobalBlock which describe the global blocks owned
3643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   by the shared object characterised by the given di_handle.  Asserts
3644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if the handle is invalid.  The caller is responsible for freeing
3645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the array at some point.  If 'arrays_only' is True, only
3646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   array-typed blocks are returned; otherwise blocks of all types are
3647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   returned. */
3648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid* /* really, XArray* of GlobalBlock */
3650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(di_get_global_blocks_from_dihandle) ( ULong di_handle,
3651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                Bool  arrays_only )
3652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This is a derivation of consider_vars_in_frame() above. */
3654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* di;
3656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XArray* gvars; /* XArray* of GlobalBlock */
3657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word nScopes, scopeIx;
3658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The first thing to do is find the DebugInfo that
3660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pertains to 'di_handle'. */
3661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(di_handle > 0);
3662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (di = debugInfo_list; di; di = di->next) {
3663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di->handle == di_handle)
3664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If this fails, we were unable to find any DebugInfo with the
3668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      given handle.  This is considered an error on the part of the
3669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      caller. */
3670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(di != NULL);
3671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* we'll put the collected variables in here. */
3673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gvars = VG_(newXA)( ML_(dinfo_zalloc), "di.debuginfo.dggbfd.1",
3674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       ML_(dinfo_free), sizeof(GlobalBlock) );
3675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(gvars);
3676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* any var info at all? */
3678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!di->varinfo)
3679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return gvars;
3680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* we'll iterate over all the variables we can find, even if
3682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      it seems senseless to visit stack-allocated variables */
3683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Iterate over all scopes */
3684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   nScopes = VG_(sizeXA)( di->varinfo );
3685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (scopeIx = 0; scopeIx < nScopes; scopeIx++) {
3686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Iterate over each (code) address range at the current scope */
3688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DiAddrRange* range;
3689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      OSet* /* of DiAddrInfo */ scope
3690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = *(OSet**)VG_(indexXA)( di->varinfo, scopeIx );
3691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(scope);
3692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(OSetGen_ResetIter)(scope);
3693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      while ( (range = VG_(OSetGen_Next)(scope)) ) {
3694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Iterate over each variable in the current address range */
3696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Word nVars, varIx;
3697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(range->vars);
3698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nVars = VG_(sizeXA)( range->vars );
3699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (varIx = 0; varIx < nVars; varIx++) {
3700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Bool        isVec;
3702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            GXResult    res;
3703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            MaybeULong  mul;
3704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            GlobalBlock gb;
3705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            TyEnt*      ty;
3706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DiVariable* var = VG_(indexXA)( range->vars, varIx );
3707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(var->name);
3708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (0) VG_(printf)("at depth %ld var %s ", scopeIx, var->name );
3709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Now figure out if this variable has a constant address
3711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (that is, independent of FP, SP, phase of moon, etc),
3712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               and if so, what the address is.  Any variable with a
3713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               constant address is deemed to be a global so we collect
3714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               it. */
3715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (0) { VG_(printf)("EVAL: "); ML_(pp_GX)(var->gexpr);
3716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     VG_(printf)("\n"); }
3717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            res = ML_(evaluate_trivial_GX)( var->gexpr, di );
3718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Not a constant address => not interesting */
3720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (res.kind != GXR_Addr) {
3721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (0) VG_(printf)("FAIL\n");
3722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               continue;
3723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Ok, it's a constant address.  See if we want to collect
3726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               it. */
3727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (0) VG_(printf)("%#lx\n", res.word);
3728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Figure out how big the variable is. */
3730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mul = ML_(sizeOfType)(di->admin_tyents, var->typeR);
3731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* If this var has a type whose size is unknown, zero, or
3733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               impossibly large, it should never have been added.
3734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               ML_(addVar) should have rejected it. */
3735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vg_assert(mul.b == True);
3736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vg_assert(mul.ul > 0);
3737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (sizeof(void*) == 4) vg_assert(mul.ul < (1ULL << 32));
3738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* After this point, we assume we can truncate mul.ul to a
3739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               host word safely (without loss of info). */
3740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* skip if non-array and we're only interested in
3742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               arrays */
3743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ty = ML_(TyEnts__index_by_cuOff)( di->admin_tyents, NULL,
3744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              var->typeR );
3745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vg_assert(ty);
3746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vg_assert(ty->tag == Te_UNKNOWN || ML_(TyEnt__is_type)(ty));
3747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (ty->tag == Te_UNKNOWN)
3748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               continue; /* perhaps we should complain in this case? */
3749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            isVec = ty->tag == Te_TyArray;
3751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (arrays_only && !isVec) continue;
3752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Ok, so collect it! */
3754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(var->name);
3755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(di->soname);
3756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (0) VG_(printf)("XXXX %s %s %d\n", var->name,
3757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                var->fileName?(HChar*)var->fileName
3758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             :"??",var->lineNo);
3759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(memset)(&gb, 0, sizeof(gb));
3760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gb.addr  = res.word;
3761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gb.szB   = (SizeT)mul.ul;
3762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gb.isVec = isVec;
3763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(strncpy)(&gb.name[0], var->name, sizeof(gb.name)-1);
3764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(strncpy)(&gb.soname[0], di->soname, sizeof(gb.soname)-1);
3765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(gb.name[ sizeof(gb.name)-1 ] == 0);
3766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(gb.soname[ sizeof(gb.soname)-1 ] == 0);
3767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(addToXA)( gvars, &gb );
3769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } /* for (varIx = 0; varIx < nVars; varIx++) */
3771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } /* while ( (range = VG_(OSetGen_Next)(scope)) ) */
3773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* for (scopeIx = 0; scopeIx < nScopes; scopeIx++) */
3775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return gvars;
3777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
3781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- DebugInfo accessor functions                         ---*/
3782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
3783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownconst DebugInfo* VG_(next_DebugInfo)(const DebugInfo* di)
3785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (di == NULL)
3787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return debugInfo_list;
3788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return di->next;
3789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownAddr VG_(DebugInfo_get_text_avma)(const DebugInfo* di)
3792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return di->text_present ? di->text_avma : 0;
3794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSizeT VG_(DebugInfo_get_text_size)(const DebugInfo* di)
3797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return di->text_present ? di->text_size : 0;
3799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3801436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovAddr VG_(DebugInfo_get_bss_avma)(const DebugInfo* di)
3802436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
3803436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return di->bss_present ? di->bss_avma : 0;
3804436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
3805436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
3806436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovSizeT VG_(DebugInfo_get_bss_size)(const DebugInfo* di)
3807436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
3808436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return di->bss_present ? di->bss_size : 0;
3809436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
3810436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
3811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownAddr VG_(DebugInfo_get_plt_avma)(const DebugInfo* di)
3812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return di->plt_present ? di->plt_avma : 0;
3814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSizeT VG_(DebugInfo_get_plt_size)(const DebugInfo* di)
3817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return di->plt_present ? di->plt_size : 0;
3819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownAddr VG_(DebugInfo_get_gotplt_avma)(const DebugInfo* di)
3822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return di->gotplt_present ? di->gotplt_avma : 0;
3824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSizeT VG_(DebugInfo_get_gotplt_size)(const DebugInfo* di)
3827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return di->gotplt_present ? di->gotplt_size : 0;
3829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3831436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovAddr VG_(DebugInfo_get_got_avma)(const DebugInfo* di)
3832436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
3833436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return di->got_present ? di->got_avma : 0;
3834436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
3835436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
3836436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovSizeT VG_(DebugInfo_get_got_size)(const DebugInfo* di)
3837436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
3838436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return di->got_present ? di->got_size : 0;
3839436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
3840436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
3841436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovconst HChar* VG_(DebugInfo_get_soname)(const DebugInfo* di)
3842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return di->soname;
3844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3846436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovconst HChar* VG_(DebugInfo_get_filename)(const DebugInfo* di)
3847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3848b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return di->fsm.filename;
3849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownPtrdiffT VG_(DebugInfo_get_text_bias)(const DebugInfo* di)
3852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return di->text_present ? di->text_bias : 0;
3854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(DebugInfo_syms_howmany) ( const DebugInfo *si )
3857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return si->symtab_used;
3859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(DebugInfo_syms_getidx) ( const DebugInfo *si,
3862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        Int idx,
3863b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                  /*OUT*/Addr*    avma,
3864b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                  /*OUT*/Addr*    tocptr,
3865b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                  /*OUT*/UInt*    size,
3866436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                  /*OUT*/HChar**  pri_name,
3867436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                  /*OUT*/HChar*** sec_names,
3868b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                  /*OUT*/Bool*    isText,
3869b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                  /*OUT*/Bool*    isIFunc )
3870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(idx >= 0 && idx < si->symtab_used);
3872b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (avma)      *avma      = si->symtab[idx].addr;
3873b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (tocptr)    *tocptr    = si->symtab[idx].tocptr;
3874b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (size)      *size      = si->symtab[idx].size;
3875b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (pri_name)  *pri_name  = si->symtab[idx].pri_name;
3876436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sec_names) *sec_names = (HChar **)si->symtab[idx].sec_names; // FIXME
3877b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (isText)    *isText    = si->symtab[idx].isText;
3878b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (isIFunc)   *isIFunc   = si->symtab[idx].isIFunc;
3879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
3883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- SectKind query functions                             ---*/
3884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
3885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Convert a VgSectKind to a string, which must be copied if you want
3887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to change it. */
3888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownconst HChar* VG_(pp_SectKind)( VgSectKind kind )
3889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (kind) {
3891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Vg_SectUnknown: return "Unknown";
3892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Vg_SectText:    return "Text";
3893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Vg_SectData:    return "Data";
3894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Vg_SectBSS:     return "BSS";
3895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Vg_SectGOT:     return "GOT";
3896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Vg_SectPLT:     return "PLT";
3897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Vg_SectOPD:     return "OPD";
3898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Vg_SectGOTPLT:  return "GOTPLT";
3899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:             vg_assert(0);
3900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given an address 'a', make a guess of which section of which object
3904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   it comes from.  If name is non-NULL, then the last n_name-1
3905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   characters of the object's name is put in name[0 .. n_name-2], and
3906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   name[n_name-1] is set to zero (guaranteed zero terminated). */
3907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3908436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovVgSectKind VG_(DebugInfo_sect_kind)( /*OUT*/HChar* name, SizeT n_name,
3909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     Addr a)
3910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DebugInfo* di;
3912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VgSectKind res = Vg_SectUnknown;
3913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (di = debugInfo_list; di != NULL; di = di->next) {
3915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0)
3917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)(
3918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            "addr=%#lx di=%p %s got=%#lx,%ld plt=%#lx,%ld "
3919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            "data=%#lx,%ld bss=%#lx,%ld\n",
3920b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            a, di, di->fsm.filename,
3921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            di->got_avma,  di->got_size,
3922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            di->plt_avma,  di->plt_size,
3923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            di->data_avma, di->data_size,
3924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            di->bss_avma,  di->bss_size);
3925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di->text_present
3927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && di->text_size > 0
3928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a >= di->text_avma && a < di->text_avma + di->text_size) {
3929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = Vg_SectText;
3930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di->data_present
3933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && di->data_size > 0
3934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a >= di->data_avma && a < di->data_avma + di->data_size) {
3935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = Vg_SectData;
3936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di->sdata_present
3939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && di->sdata_size > 0
3940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a >= di->sdata_avma && a < di->sdata_avma + di->sdata_size) {
3941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = Vg_SectData;
3942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di->bss_present
3945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && di->bss_size > 0
3946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a >= di->bss_avma && a < di->bss_avma + di->bss_size) {
3947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = Vg_SectBSS;
3948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di->sbss_present
3951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && di->sbss_size > 0
3952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a >= di->sbss_avma && a < di->sbss_avma + di->sbss_size) {
3953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = Vg_SectBSS;
3954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di->plt_present
3957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && di->plt_size > 0
3958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a >= di->plt_avma && a < di->plt_avma + di->plt_size) {
3959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = Vg_SectPLT;
3960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di->got_present
3963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && di->got_size > 0
3964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a >= di->got_avma && a < di->got_avma + di->got_size) {
3965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = Vg_SectGOT;
3966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di->gotplt_present
3969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && di->gotplt_size > 0
3970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a >= di->gotplt_avma && a < di->gotplt_avma + di->gotplt_size) {
3971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = Vg_SectGOTPLT;
3972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (di->opd_present
3975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && di->opd_size > 0
3976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a >= di->opd_avma && a < di->opd_avma + di->opd_size) {
3977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res = Vg_SectOPD;
3978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* we could also check for .eh_frame, if anyone really cares */
3981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert( (di == NULL && res == Vg_SectUnknown)
3984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              || (di != NULL && res != Vg_SectUnknown) );
3985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (name) {
3987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(n_name >= 8);
3989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3990b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (di && di->fsm.filename) {
3991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int i, j;
3992b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         Int fnlen = VG_(strlen)(di->fsm.filename);
3993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int start_at = 1 + fnlen - n_name;
3994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (start_at < 0) start_at = 0;
3995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(start_at < fnlen);
3996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         i = start_at; j = 0;
3997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         while (True) {
3998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vg_assert(j >= 0 && j < n_name);
3999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vg_assert(i >= 0 && i <= fnlen);
4000b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            name[j] = di->fsm.filename[i];
4001b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            if (di->fsm.filename[i] == 0) break;
4002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            i++; j++;
4003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(i == fnlen);
4005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
4006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(snprintf)(name, n_name, "%s", "???");
4007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      name[n_name-1] = 0;
4010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res;
4013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
4017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                                          ---*/
4018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
4019