blob: d7d9d165fe8bf30017933000a3589298dda8d922 [file] [log] [blame]
sewardj267100d2005-04-24 12:33:12 +00001
njnd01fef72005-03-25 23:35:48 +00002/*--------------------------------------------------------------------*/
sewardj267100d2005-04-24 12:33:12 +00003/*--- Take snapshots of client stacks. m_stacktrace.c ---*/
njnd01fef72005-03-25 23:35:48 +00004/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
sewardje4b0bf02006-06-05 23:21:15 +000010 Copyright (C) 2000-2006 Julian Seward
njnd01fef72005-03-25 23:35:48 +000011 jseward@acm.org
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
njnc7561b92005-06-19 01:24:32 +000031#include "pub_core_basics.h"
sewardj4cfea4f2006-10-14 19:26:10 +000032#include "pub_core_vki.h"
njnc7561b92005-06-19 01:24:32 +000033#include "pub_core_threadstate.h"
njn88c51482005-06-25 20:49:33 +000034#include "pub_core_debuginfo.h"
njn24a6efb2005-06-20 03:36:51 +000035#include "pub_core_aspacemgr.h" // For VG_(is_addressable)()
njn97405b22005-06-02 03:39:33 +000036#include "pub_core_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000037#include "pub_core_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000038#include "pub_core_libcprint.h"
njnf536bbb2005-06-13 04:21:38 +000039#include "pub_core_machine.h"
njn20242342005-05-16 23:31:24 +000040#include "pub_core_options.h"
njnd01fef72005-03-25 23:35:48 +000041#include "pub_core_stacktrace.h"
sewardja672ea32006-04-29 18:03:14 +000042#include "pub_core_clientstate.h" // VG_(client__dl_sysinfo_int80)
njna7598f62005-06-18 03:27:58 +000043#include "pub_core_trampoline.h"
njnd01fef72005-03-25 23:35:48 +000044
45/*------------------------------------------------------------*/
46/*--- Exported functions. ---*/
47/*------------------------------------------------------------*/
48
sewardjacaec5f2005-08-19 16:02:59 +000049/* Take a snapshot of the client's stack, putting the up to 'n_ips'
50 IPs into 'ips'. In order to be thread-safe, we pass in the
51 thread's IP SP, FP if that's meaningful, and LR if that's
52 meaningful. Returns number of IPs put in 'ips'.
sewardjdfbaa222006-01-18 04:25:20 +000053
54 If you know what the thread ID for this stack is, send that as the
55 first parameter, else send zero. This helps generate better stack
56 traces on ppc64-linux and has no effect on other platforms.
sewardjacaec5f2005-08-19 16:02:59 +000057*/
sewardjdfbaa222006-01-18 04:25:20 +000058UInt VG_(get_StackTrace2) ( ThreadId tid_if_known,
59 Addr* ips, UInt n_ips,
sewardjacaec5f2005-08-19 16:02:59 +000060 Addr ip, Addr sp, Addr fp, Addr lr,
njnd01fef72005-03-25 23:35:48 +000061 Addr fp_min, Addr fp_max_orig )
62{
sewardj2c48c7b2005-11-29 13:05:56 +000063#if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
sewardjacaec5f2005-08-19 16:02:59 +000064 Bool lr_is_first_RA = False; /* ppc only */
njn2a3b9292005-08-24 01:56:15 +000065#endif
sewardjacaec5f2005-08-19 16:02:59 +000066 Bool debug = False;
67 Int i;
68 Addr fp_max;
69 UInt n_found = 0;
njnd01fef72005-03-25 23:35:48 +000070
sewardjacaec5f2005-08-19 16:02:59 +000071 vg_assert(sizeof(Addr) == sizeof(UWord));
72 vg_assert(sizeof(Addr) == sizeof(void*));
njnd01fef72005-03-25 23:35:48 +000073
sewardjacaec5f2005-08-19 16:02:59 +000074 /* Snaffle IPs from the client's stack into ips[0 .. n_ips-1],
njnc0ec8e92005-12-25 06:34:04 +000075 stopping when the trail goes cold, which we guess to be
sewardjacaec5f2005-08-19 16:02:59 +000076 when FP is not a reasonable stack location. */
77
njnd01fef72005-03-25 23:35:48 +000078 // JRS 2002-sep-17: hack, to round up fp_max to the end of the
79 // current page, at least. Dunno if it helps.
80 // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again
sewardj45f4e7c2005-09-27 19:20:21 +000081 fp_max = VG_PGROUNDUP(fp_max_orig);
njnd01fef72005-03-25 23:35:48 +000082 fp_max -= sizeof(Addr);
83
84 if (debug)
85 VG_(printf)("n_ips=%d fp_min=%p fp_max_orig=%p, fp_max=%p ip=%p fp=%p\n",
86 n_ips, fp_min, fp_max_orig, fp_max, ip, fp);
87
88 /* Assertion broken before main() is reached in pthreaded programs; the
89 * offending stack traces only have one item. --njn, 2002-aug-16 */
90 /* vg_assert(fp_min <= fp_max);*/
91
sewardj35165532005-04-30 18:47:48 +000092 if (fp_min + VG_(clo_max_stackframe) <= fp_max) {
njnd01fef72005-03-25 23:35:48 +000093 /* If the stack is ridiculously big, don't poke around ... but
94 don't bomb out either. Needed to make John Regehr's
95 user-space threads package work. JRS 20021001 */
sewardjacaec5f2005-08-19 16:02:59 +000096 ips[0] = ip;
sewardjacaec5f2005-08-19 16:02:59 +000097 return 1;
98 }
sewardj35165532005-04-30 18:47:48 +000099
sewardjacaec5f2005-08-19 16:02:59 +0000100 /* Otherwise unwind the stack in a platform-specific way. Trying
sewardjdb2ac812005-12-23 23:33:51 +0000101 to merge the x86, amd64, ppc32 and ppc64 logic into a single
102 piece of code is just too confusing and difficult to
103 performance-tune. */
njn88b5a982005-05-16 00:16:56 +0000104
sewardj75ea7982005-11-14 15:18:25 +0000105# if defined(VGP_x86_linux)
sewardj35165532005-04-30 18:47:48 +0000106
sewardj75ea7982005-11-14 15:18:25 +0000107 /*--------------------- x86 ---------------------*/
sewardj35165532005-04-30 18:47:48 +0000108
sewardj75ea7982005-11-14 15:18:25 +0000109 /* fp is %ebp. sp is %esp. ip is %eip. */
110
111 ips[0] = ip;
112 i = 1;
113
114 /* Loop unwinding the stack. Note that the IP value we get on
115 * each pass (whether from CFI info or a stack frame) is a
116 * return address so is actually after the calling instruction
117 * in the calling function.
118 *
119 * Because of this we subtract one from the IP after each pass
120 * of the loop so that we find the right CFI block on the next
121 * pass - otherwise we can find the wrong CFI info if it happens
122 * to change after the calling instruction and that will mean
123 * that we will fail to unwind the next step.
124 *
125 * This most frequently happens at the end of a function when
126 * a tail call occurs and we wind up using the CFI info for the
127 * next function which is completely wrong.
128 */
129 while (True) {
130
131 if (i >= n_ips)
132 break;
133
134 /* Try to derive a new (ip,sp,fp) triple from the current
135 set. */
136
137 /* On x86, first try the old-fashioned method of following the
138 %ebp-chain. Code which doesn't use this (that is, compiled
139 with -fomit-frame-pointer) is not ABI compliant and so
140 relatively rare. Besides, trying the CFI first almost always
141 fails, and is expensive. */
142 /* Deal with frames resulting from functions which begin "pushl%
143 ebp ; movl %esp, %ebp" which is the ABI-mandated preamble. */
144 if (fp_min <= fp && fp <= fp_max) {
145 /* fp looks sane, so use it. */
146 ip = (((UWord*)fp)[1]);
147 sp = fp + sizeof(Addr) /*saved %ebp*/
148 + sizeof(Addr) /*ra*/;
149 fp = (((UWord*)fp)[0]);
150 ips[i++] = ip;
151 if (debug)
152 VG_(printf)(" ipsF[%d]=%08p\n", i-1, ips[i-1]);
153 ip = ip - 1;
154 continue;
155 }
156
157 /* That didn't work out, so see if there is any CFI info to hand
158 which can be used. */
sewardjeadcd862006-04-04 15:12:44 +0000159 if ( VG_(use_CF_info)( &ip, &sp, &fp, fp_min, fp_max ) ) {
sewardj75ea7982005-11-14 15:18:25 +0000160 ips[i++] = ip;
161 if (debug)
162 VG_(printf)(" ipsC[%d]=%08p\n", i-1, ips[i-1]);
163 ip = ip - 1;
164 continue;
165 }
166
167 /* No luck. We have to give up. */
168 break;
169 }
170
171# elif defined(VGP_amd64_linux)
172
173 /*--------------------- amd64 ---------------------*/
174
175 /* fp is %rbp. sp is %rsp. ip is %rip. */
sewardj35165532005-04-30 18:47:48 +0000176
sewardjacaec5f2005-08-19 16:02:59 +0000177 ips[0] = ip;
178 i = 1;
sewardj35165532005-04-30 18:47:48 +0000179
tomac35f102005-11-05 00:17:21 +0000180 /* Loop unwinding the stack. Note that the IP value we get on
181 * each pass (whether from CFI info or a stack frame) is a
182 * return address so is actually after the calling instruction
183 * in the calling function.
184 *
185 * Because of this we subtract one from the IP after each pass
186 * of the loop so that we find the right CFI block on the next
187 * pass - otherwise we can find the wrong CFI info if it happens
188 * to change after the calling instruction and that will mean
189 * that we will fail to unwind the next step.
190 *
191 * This most frequently happens at the end of a function when
192 * a tail call occurs and we wind up using the CFI info for the
193 * next function which is completely wrong.
194 */
sewardjacaec5f2005-08-19 16:02:59 +0000195 while (True) {
sewardj35165532005-04-30 18:47:48 +0000196
sewardjacaec5f2005-08-19 16:02:59 +0000197 if (i >= n_ips)
sewardj35165532005-04-30 18:47:48 +0000198 break;
sewardjacaec5f2005-08-19 16:02:59 +0000199
200 /* Try to derive a new (ip,sp,fp) triple from the current
201 set. */
202
203 /* First off, see if there is any CFI info to hand which can
204 be used. */
sewardjeadcd862006-04-04 15:12:44 +0000205 if ( VG_(use_CF_info)( &ip, &sp, &fp, fp_min, fp_max ) ) {
sewardjacaec5f2005-08-19 16:02:59 +0000206 ips[i++] = ip;
207 if (debug)
208 VG_(printf)(" ipsC[%d]=%08p\n", i-1, ips[i-1]);
tom121d1d02005-11-04 11:31:33 +0000209 ip = ip - 1;
sewardjacaec5f2005-08-19 16:02:59 +0000210 continue;
njnd01fef72005-03-25 23:35:48 +0000211 }
sewardj35165532005-04-30 18:47:48 +0000212
sewardjeadcd862006-04-04 15:12:44 +0000213 /* If VG_(use_CF_info) fails, it won't modify ip/sp/fp, so
sewardjacaec5f2005-08-19 16:02:59 +0000214 we can safely try the old-fashioned method. */
215 /* This bit is supposed to deal with frames resulting from
sewardj75ea7982005-11-14 15:18:25 +0000216 functions which begin "pushq %rbp ; movq %rsp, %rbp".
217 Unfortunately, since we can't (easily) look at the insns at
218 the start of the fn, like GDB does, there's no reliable way
219 to tell. Hence the hack of first trying out CFI, and if that
220 fails, then use this as a fallback. */
sewardjacaec5f2005-08-19 16:02:59 +0000221 if (fp_min <= fp && fp <= fp_max) {
222 /* fp looks sane, so use it. */
223 ip = (((UWord*)fp)[1]);
sewardj75ea7982005-11-14 15:18:25 +0000224 sp = fp + sizeof(Addr) /*saved %rbp*/
sewardjacaec5f2005-08-19 16:02:59 +0000225 + sizeof(Addr) /*ra*/;
226 fp = (((UWord*)fp)[0]);
227 ips[i++] = ip;
228 if (debug)
229 VG_(printf)(" ipsF[%d]=%08p\n", i-1, ips[i-1]);
tom121d1d02005-11-04 11:31:33 +0000230 ip = ip - 1;
sewardjacaec5f2005-08-19 16:02:59 +0000231 continue;
232 }
233
234 /* No luck there. We have to give up. */
235 break;
njnd01fef72005-03-25 23:35:48 +0000236 }
sewardjacaec5f2005-08-19 16:02:59 +0000237
sewardj2c48c7b2005-11-29 13:05:56 +0000238# elif defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
sewardjacaec5f2005-08-19 16:02:59 +0000239
sewardjdfbaa222006-01-18 04:25:20 +0000240 /*--------------------- ppc32/64 ---------------------*/
sewardj75ea7982005-11-14 15:18:25 +0000241
sewardjacaec5f2005-08-19 16:02:59 +0000242 /* fp is %r1. ip is %cia. Note, ppc uses r1 as both the stack and
243 frame pointers. */
244
sewardjcfb5e2b2006-01-19 03:47:30 +0000245# if defined(VGP_ppc64_linux)
246 /* Deal with bogus LR values caused by function
247 interception/wrapping; see comment on similar code a few lines
248 further down. */
249 if (lr == (Addr)&VG_(ppc64_linux_magic_redirect_return_stub)
250 && VG_(is_valid_tid)(tid_if_known)) {
251 Long hsp = VG_(threads)[tid_if_known].arch.vex.guest_REDIR_SP;
252 if (hsp >= 1 && hsp < VEX_GUEST_PPC64_REDIR_STACK_SIZE)
253 lr = VG_(threads)[tid_if_known]
254 .arch.vex.guest_REDIR_STACK[hsp-1];
255 }
256# endif
257
sewardjacaec5f2005-08-19 16:02:59 +0000258 lr_is_first_RA = False;
259 {
260# define M_VG_ERRTXT 1000
261 UChar buf_lr[M_VG_ERRTXT], buf_ip[M_VG_ERRTXT];
262 if (VG_(get_fnname_nodemangle) (lr, buf_lr, M_VG_ERRTXT))
263 if (VG_(get_fnname_nodemangle) (ip, buf_ip, M_VG_ERRTXT))
264 if (VG_(strncmp)(buf_lr, buf_ip, M_VG_ERRTXT))
265 lr_is_first_RA = True;
266# undef M_VG_ERRTXT
267 }
268
269 ips[0] = ip;
270 i = 1;
sewardjacaec5f2005-08-19 16:02:59 +0000271
sewardjdb2ac812005-12-23 23:33:51 +0000272 if (fp_min <= fp && fp < fp_max-VG_WORDSIZE+1) {
sewardjacaec5f2005-08-19 16:02:59 +0000273
sewardj525e2322005-11-13 02:41:35 +0000274 /* initial FP is sane; keep going */
275 fp = (((UWord*)fp)[0]);
276
277 while (True) {
278
sewardjdb2ac812005-12-23 23:33:51 +0000279 /* on ppc64-linux (ppc64-elf, really), the lr save slot is 2
280 words back from sp, whereas on ppc32-elf(?) it's only one
281 word back. */
sewardjdfbaa222006-01-18 04:25:20 +0000282# if defined(VGP_ppc64_linux)
283 const Int lr_offset = 2;
284# else
285 const Int lr_offset = 1;
286# endif
sewardjdb2ac812005-12-23 23:33:51 +0000287
sewardj525e2322005-11-13 02:41:35 +0000288 if (i >= n_ips)
289 break;
290
291 /* Try to derive a new (ip,fp) pair from the current set. */
292
293 if (fp_min <= fp && fp <= fp_max) {
294 /* fp looks sane, so use it. */
295
296 if (i == 1 && lr_is_first_RA)
297 ip = lr;
298 else
sewardjdb2ac812005-12-23 23:33:51 +0000299 ip = (((UWord*)fp)[lr_offset]);
sewardj525e2322005-11-13 02:41:35 +0000300
sewardjdfbaa222006-01-18 04:25:20 +0000301# if defined(VGP_ppc64_linux)
302 /* Nasty hack to do with function replacement/wrapping on
303 ppc64-linux. If LR points to our magic return stub,
304 then we are in a wrapped or intercepted function, in
305 which LR has been messed with. The original LR will
306 have been pushed onto the thread's hidden REDIR stack
307 one down from the top (top element is the saved R2) and
308 so we should restore the value from there instead. */
309 if (i == 1
310 && ip == (Addr)&VG_(ppc64_linux_magic_redirect_return_stub)
311 && VG_(is_valid_tid)(tid_if_known)) {
312 Long hsp = VG_(threads)[tid_if_known].arch.vex.guest_REDIR_SP;
313 if (hsp >= 1 && hsp < VEX_GUEST_PPC64_REDIR_STACK_SIZE)
314 ip = VG_(threads)[tid_if_known]
315 .arch.vex.guest_REDIR_STACK[hsp-1];
316 }
317# endif
318
sewardj525e2322005-11-13 02:41:35 +0000319 fp = (((UWord*)fp)[0]);
320 ips[i++] = ip;
321 if (debug)
322 VG_(printf)(" ipsF[%d]=%08p\n", i-1, ips[i-1]);
323 continue;
324 }
325
326 /* No luck there. We have to give up. */
sewardjacaec5f2005-08-19 16:02:59 +0000327 break;
sewardjacaec5f2005-08-19 16:02:59 +0000328 }
sewardjacaec5f2005-08-19 16:02:59 +0000329 }
330
331# else
332# error "Unknown platform"
333# endif
334
njnd01fef72005-03-25 23:35:48 +0000335 n_found = i;
njnd01fef72005-03-25 23:35:48 +0000336 return n_found;
337}
338
339UInt VG_(get_StackTrace) ( ThreadId tid, StackTrace ips, UInt n_ips )
340{
341 /* thread in thread table */
njnf536bbb2005-06-13 04:21:38 +0000342 Addr ip = VG_(get_IP)(tid);
343 Addr fp = VG_(get_FP)(tid);
344 Addr sp = VG_(get_SP)(tid);
sewardjacaec5f2005-08-19 16:02:59 +0000345 Addr lr = VG_(get_LR)(tid);
njnf536bbb2005-06-13 04:21:38 +0000346 Addr stack_highest_word = VG_(threads)[tid].client_stack_highest_word;
njnd01fef72005-03-25 23:35:48 +0000347
sewardjb9bce632005-06-21 01:41:34 +0000348# if defined(VGP_x86_linux)
sewardja672ea32006-04-29 18:03:14 +0000349 /* Nasty little hack to deal with syscalls - if libc is using its
350 _dl_sysinfo_int80 function for syscalls (the TLS version does),
351 then ip will always appear to be in that function when doing a
352 syscall, not the actual libc function doing the syscall. This
353 check sees if IP is within that function, and pops the return
354 address off the stack so that ip is placed within the library
355 function calling the syscall. This makes stack backtraces much
356 more useful.
357
358 The function is assumed to look like this (from glibc-2.3.6 sources):
359 _dl_sysinfo_int80:
360 int $0x80
361 ret
362 That is 3 (2+1) bytes long. We could be more thorough and check
363 the 3 bytes of the function are as expected, but I can't be
364 bothered.
365 */
366 if (VG_(client__dl_sysinfo_int80) != 0 /* we know its address */
367 && ip >= VG_(client__dl_sysinfo_int80)
368 && ip < VG_(client__dl_sysinfo_int80)+3
sewardj45f4e7c2005-09-27 19:20:21 +0000369 && VG_(am_is_valid_for_client)(sp, sizeof(Addr), VKI_PROT_READ)) {
njnd01fef72005-03-25 23:35:48 +0000370 ip = *(Addr *)sp;
371 sp += sizeof(Addr);
372 }
sewardjb9bce632005-06-21 01:41:34 +0000373# endif
374
njnd01fef72005-03-25 23:35:48 +0000375 if (0)
376 VG_(printf)("tid %d: stack_highest=%p ip=%p sp=%p fp=%p\n",
377 tid, stack_highest_word, ip, sp, fp);
378
sewardjdfbaa222006-01-18 04:25:20 +0000379 return VG_(get_StackTrace2)(tid, ips, n_ips, ip, sp, fp, lr, sp,
380 stack_highest_word);
njnd01fef72005-03-25 23:35:48 +0000381}
382
383static void printIpDesc(UInt n, Addr ip)
384{
njn83f9e792005-06-11 05:04:09 +0000385 #define BUF_LEN 4096
386
387 static UChar buf[BUF_LEN];
njnd01fef72005-03-25 23:35:48 +0000388
njn83f9e792005-06-11 05:04:09 +0000389 VG_(describe_IP)(ip, buf, BUF_LEN);
sewardj71bc3cb2005-05-19 00:25:45 +0000390
391 if (VG_(clo_xml)) {
392 VG_(message)(Vg_UserMsg, " %s", buf);
393 } else {
394 VG_(message)(Vg_UserMsg, " %s %s", ( n == 0 ? "at" : "by" ), buf);
395 }
njnd01fef72005-03-25 23:35:48 +0000396}
397
398/* Print a StackTrace. */
399void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips )
400{
401 vg_assert( n_ips > 0 );
sewardj71bc3cb2005-05-19 00:25:45 +0000402
403 if (VG_(clo_xml))
404 VG_(message)(Vg_UserMsg, " <stack>");
405
njnd01fef72005-03-25 23:35:48 +0000406 VG_(apply_StackTrace)( printIpDesc, ips, n_ips );
sewardj71bc3cb2005-05-19 00:25:45 +0000407
408 if (VG_(clo_xml))
409 VG_(message)(Vg_UserMsg, " </stack>");
njnd01fef72005-03-25 23:35:48 +0000410}
411
412/* Get and immediately print a StackTrace. */
413void VG_(get_and_pp_StackTrace) ( ThreadId tid, UInt n_ips )
414{
415 Addr ips[n_ips];
njn88d3ba82006-08-13 04:48:25 +0000416 UInt n_ips_obtained = VG_(get_StackTrace)(tid, ips, n_ips);
417 VG_(pp_StackTrace)(ips, n_ips_obtained);
njnd01fef72005-03-25 23:35:48 +0000418}
419
420
421void VG_(apply_StackTrace)( void(*action)(UInt n, Addr ip),
422 StackTrace ips, UInt n_ips )
423{
sewardj73cf4c62005-11-17 15:12:34 +0000424 #define MYBUF_LEN 50 // only needs to be long enough for
425 // the names specially tested for
njnd01fef72005-03-25 23:35:48 +0000426
427 Bool main_done = False;
428 Char mybuf[MYBUF_LEN]; // ok to stack allocate mybuf[] -- it's tiny
429 Int i = 0;
430
431 vg_assert(n_ips > 0);
432 do {
433 Addr ip = ips[i];
434 if (i > 0)
njnaf839f52005-06-23 03:27:57 +0000435 ip -= VG_MIN_INSTR_SZB; // point to calling line
njnd01fef72005-03-25 23:35:48 +0000436
sewardj73cf4c62005-11-17 15:12:34 +0000437 // Stop after the first appearance of "main" or one of the other names
438 // (the appearance of which is a pretty good sign that we've gone past
439 // main without seeing it, for whatever reason)
njnd01fef72005-03-25 23:35:48 +0000440 if ( ! VG_(clo_show_below_main)) {
441 VG_(get_fnname_nodemangle)( ip, mybuf, MYBUF_LEN );
sewardj73cf4c62005-11-17 15:12:34 +0000442 mybuf[MYBUF_LEN-1] = 0; // paranoia
443 if ( VG_STREQ("main", mybuf)
444# if defined(VGO_linux)
sewardj1a85f4f2006-01-12 21:15:35 +0000445 || VG_STREQ("__libc_start_main", mybuf) // glibc glibness
446 || VG_STREQ("generic_start_main", mybuf) // Yellow Dog doggedness
sewardj73cf4c62005-11-17 15:12:34 +0000447# endif
448 )
njnd01fef72005-03-25 23:35:48 +0000449 main_done = True;
njnd01fef72005-03-25 23:35:48 +0000450 }
451
452 // Act on the ip
453 action(i, ip);
454
455 i++;
sewardj73cf4c62005-11-17 15:12:34 +0000456 } while (i < n_ips && ips[i] != 0 && !main_done);
njnd01fef72005-03-25 23:35:48 +0000457
458 #undef MYBUF_LEN
459}
460
461
462/*--------------------------------------------------------------------*/
njn24a6efb2005-06-20 03:36:51 +0000463/*--- end ---*/
njnd01fef72005-03-25 23:35:48 +0000464/*--------------------------------------------------------------------*/