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