]>
Commit | Line | Data |
---|---|---|
bd5635a1 RP |
1 | /* Get info from stack frames; |
2 | convert between frames, blocks, functions and pc values. | |
3 | Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc. | |
4 | ||
5 | This file is part of GDB. | |
6 | ||
5259796b | 7 | This program is free software; you can redistribute it and/or modify |
bd5635a1 | 8 | it under the terms of the GNU General Public License as published by |
5259796b JG |
9 | the Free Software Foundation; either version 2 of the License, or |
10 | (at your option) any later version. | |
bd5635a1 | 11 | |
5259796b | 12 | This program is distributed in the hope that it will be useful, |
bd5635a1 RP |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
5259796b JG |
18 | along with this program; if not, write to the Free Software |
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
bd5635a1 | 20 | |
d11c44f1 | 21 | #include <stdio.h> |
bd5635a1 RP |
22 | #include "defs.h" |
23 | #include "param.h" | |
24 | #include "symtab.h" | |
25 | #include "frame.h" | |
26 | #include "gdbcore.h" | |
27 | #include "value.h" /* for read_register */ | |
28 | #include "target.h" /* for target_has_stack */ | |
29 | ||
30 | /* Required by INIT_EXTRA_FRAME_INFO on 88k. */ | |
31 | #include <setjmp.h> | |
32 | #include <obstack.h> | |
33 | ||
34 | CORE_ADDR read_pc (); /* In infcmd.c */ | |
35 | ||
36 | /* Start and end of object file containing the entry point. | |
37 | STARTUP_FILE_END is the first address of the next file. | |
38 | This file is assumed to be a startup file | |
39 | and frames with pc's inside it | |
40 | are treated as nonexistent. | |
41 | ||
42 | Setting these variables is necessary so that backtraces do not fly off | |
43 | the bottom of the stack. */ | |
44 | CORE_ADDR startup_file_start; | |
45 | CORE_ADDR startup_file_end; | |
46 | ||
47 | /* Is ADDR outside the startup file? Note that if your machine | |
48 | has a way to detect the bottom of the stack, there is no need | |
49 | to call this function from FRAME_CHAIN_VALID; the reason for | |
50 | doing so is that some machines have no way of detecting bottom | |
51 | of stack. */ | |
52 | int | |
53 | outside_startup_file (addr) | |
54 | CORE_ADDR addr; | |
55 | { | |
56 | return !(addr >= startup_file_start && addr < startup_file_end); | |
57 | } | |
58 | ||
59 | /* Address of innermost stack frame (contents of FP register) */ | |
60 | ||
61 | static FRAME current_frame; | |
62 | ||
63 | /* | |
64 | * Cache for frame addresses already read by gdb. Valid only while | |
65 | * inferior is stopped. Control variables for the frame cache should | |
66 | * be local to this module. | |
67 | */ | |
68 | struct obstack frame_cache_obstack; | |
69 | ||
70 | /* Return the innermost (currently executing) stack frame. */ | |
71 | ||
72 | FRAME | |
73 | get_current_frame () | |
74 | { | |
75 | /* We assume its address is kept in a general register; | |
76 | param.h says which register. */ | |
77 | ||
78 | return current_frame; | |
79 | } | |
80 | ||
81 | void | |
82 | set_current_frame (frame) | |
83 | FRAME frame; | |
84 | { | |
85 | current_frame = frame; | |
86 | } | |
87 | ||
88 | FRAME | |
89 | create_new_frame (addr, pc) | |
90 | FRAME_ADDR addr; | |
91 | CORE_ADDR pc; | |
92 | { | |
93 | struct frame_info *fci; /* Same type as FRAME */ | |
94 | ||
95 | fci = (struct frame_info *) | |
96 | obstack_alloc (&frame_cache_obstack, | |
97 | sizeof (struct frame_info)); | |
98 | ||
99 | /* Arbitrary frame */ | |
100 | fci->next = (struct frame_info *) 0; | |
101 | fci->prev = (struct frame_info *) 0; | |
102 | fci->frame = addr; | |
103 | fci->next_frame = 0; /* Since arbitrary */ | |
104 | fci->pc = pc; | |
105 | ||
106 | #ifdef INIT_EXTRA_FRAME_INFO | |
107 | INIT_EXTRA_FRAME_INFO (fci); | |
108 | #endif | |
109 | ||
110 | return fci; | |
111 | } | |
112 | ||
113 | /* Return the frame that called FRAME. | |
114 | If FRAME is the original frame (it has no caller), return 0. */ | |
115 | ||
116 | FRAME | |
117 | get_prev_frame (frame) | |
118 | FRAME frame; | |
119 | { | |
120 | /* We're allowed to know that FRAME and "struct frame_info *" are | |
121 | the same */ | |
122 | return get_prev_frame_info (frame); | |
123 | } | |
124 | ||
125 | /* Return the frame that FRAME calls (0 if FRAME is the innermost | |
126 | frame). */ | |
127 | ||
128 | FRAME | |
129 | get_next_frame (frame) | |
130 | FRAME frame; | |
131 | { | |
132 | /* We're allowed to know that FRAME and "struct frame_info *" are | |
133 | the same */ | |
134 | return frame->next; | |
135 | } | |
136 | ||
137 | /* | |
138 | * Flush the entire frame cache. | |
139 | */ | |
140 | void | |
141 | flush_cached_frames () | |
142 | { | |
143 | /* Since we can't really be sure what the first object allocated was */ | |
144 | obstack_free (&frame_cache_obstack, 0); | |
145 | obstack_init (&frame_cache_obstack); | |
146 | ||
147 | current_frame = (struct frame_info *) 0; /* Invalidate cache */ | |
148 | } | |
149 | ||
2403f49b JK |
150 | /* Flush the frame cache, and start a new one if necessary. */ |
151 | void | |
152 | reinit_frame_cache () | |
153 | { | |
154 | FRAME fr = current_frame; | |
155 | flush_cached_frames (); | |
156 | if (fr) | |
157 | set_current_frame ( create_new_frame (read_register (FP_REGNUM), | |
158 | read_pc ())); | |
159 | } | |
160 | ||
bd5635a1 RP |
161 | /* Return a structure containing various interesting information |
162 | about a specified stack frame. */ | |
163 | /* How do I justify including this function? Well, the FRAME | |
164 | identifier format has gone through several changes recently, and | |
165 | it's not completely inconceivable that it could happen again. If | |
166 | it does, have this routine around will help */ | |
167 | ||
168 | struct frame_info * | |
169 | get_frame_info (frame) | |
170 | FRAME frame; | |
171 | { | |
172 | return frame; | |
173 | } | |
174 | ||
175 | /* If a machine allows frameless functions, it should define a macro | |
176 | FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) in param.h. FI is the struct | |
177 | frame_info for the frame, and FRAMELESS should be set to nonzero | |
178 | if it represents a frameless function invocation. */ | |
179 | ||
180 | /* Return nonzero if the function for this frame has a prologue. Many | |
181 | machines can define FRAMELESS_FUNCTION_INVOCATION to just call this | |
182 | function. */ | |
183 | ||
184 | int | |
185 | frameless_look_for_prologue (frame) | |
186 | FRAME frame; | |
187 | { | |
188 | CORE_ADDR func_start, after_prologue; | |
189 | func_start = (get_pc_function_start (frame->pc) + | |
190 | FUNCTION_START_OFFSET); | |
191 | if (func_start) | |
192 | { | |
193 | after_prologue = func_start; | |
5259796b JG |
194 | #ifdef SKIP_PROLOGUE_FRAMELESS_P |
195 | /* This is faster, since only care whether there *is* a prologue, | |
196 | not how long it is. */ | |
197 | SKIP_PROLOGUE_FRAMELESS_P (after_prologue); | |
198 | #else | |
bd5635a1 | 199 | SKIP_PROLOGUE (after_prologue); |
5259796b | 200 | #endif |
bd5635a1 RP |
201 | return after_prologue == func_start; |
202 | } | |
203 | else | |
204 | /* If we can't find the start of the function, we don't really | |
205 | know whether the function is frameless, but we should be able | |
206 | to get a reasonable (i.e. best we can do under the | |
207 | circumstances) backtrace by saying that it isn't. */ | |
208 | return 0; | |
209 | } | |
210 | ||
211 | #if !defined (INIT_FRAME_PC) | |
212 | #define INIT_FRAME_PC(fromleaf, prev) \ | |
213 | prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (prev->next) : \ | |
214 | prev->next ? FRAME_SAVED_PC (prev->next) : read_pc ()); | |
215 | #endif | |
216 | ||
217 | /* Return a structure containing various interesting information | |
218 | about the frame that called NEXT_FRAME. Returns NULL | |
219 | if there is no such frame. */ | |
220 | ||
221 | struct frame_info * | |
222 | get_prev_frame_info (next_frame) | |
223 | FRAME next_frame; | |
224 | { | |
225 | FRAME_ADDR address; | |
226 | struct frame_info *prev; | |
227 | int fromleaf = 0; | |
228 | ||
229 | /* If the requested entry is in the cache, return it. | |
230 | Otherwise, figure out what the address should be for the entry | |
231 | we're about to add to the cache. */ | |
232 | ||
233 | if (!next_frame) | |
234 | { | |
235 | if (!current_frame) | |
236 | { | |
237 | error ("You haven't set up a process's stack to examine."); | |
238 | } | |
239 | ||
240 | return current_frame; | |
241 | } | |
242 | ||
243 | /* If we have the prev one, return it */ | |
244 | if (next_frame->prev) | |
245 | return next_frame->prev; | |
246 | ||
247 | /* On some machines it is possible to call a function without | |
248 | setting up a stack frame for it. On these machines, we | |
249 | define this macro to take two args; a frameinfo pointer | |
250 | identifying a frame and a variable to set or clear if it is | |
251 | or isn't leafless. */ | |
252 | #ifdef FRAMELESS_FUNCTION_INVOCATION | |
253 | /* Still don't want to worry about this except on the innermost | |
254 | frame. This macro will set FROMLEAF if NEXT_FRAME is a | |
255 | frameless function invocation. */ | |
256 | if (!(next_frame->next)) | |
257 | { | |
258 | FRAMELESS_FUNCTION_INVOCATION (next_frame, fromleaf); | |
259 | if (fromleaf) | |
260 | address = next_frame->frame; | |
261 | } | |
262 | #endif | |
263 | ||
264 | if (!fromleaf) | |
265 | { | |
266 | /* Two macros defined in tm.h specify the machine-dependent | |
267 | actions to be performed here. | |
268 | First, get the frame's chain-pointer. | |
269 | If that is zero, the frame is the outermost frame or a leaf | |
270 | called by the outermost frame. This means that if start | |
271 | calls main without a frame, we'll return 0 (which is fine | |
272 | anyway). | |
273 | ||
274 | Nope; there's a problem. This also returns when the current | |
275 | routine is a leaf of main. This is unacceptable. We move | |
276 | this to after the ffi test; I'd rather have backtraces from | |
277 | start go curfluy than have an abort called from main not show | |
278 | main. */ | |
279 | address = FRAME_CHAIN (next_frame); | |
280 | if (!FRAME_CHAIN_VALID (address, next_frame)) | |
281 | return 0; | |
282 | address = FRAME_CHAIN_COMBINE (address, next_frame); | |
283 | } | |
284 | ||
285 | prev = (struct frame_info *) | |
286 | obstack_alloc (&frame_cache_obstack, | |
287 | sizeof (struct frame_info)); | |
288 | ||
289 | if (next_frame) | |
290 | next_frame->prev = prev; | |
291 | prev->next = next_frame; | |
292 | prev->prev = (struct frame_info *) 0; | |
293 | prev->frame = address; | |
294 | prev->next_frame = prev->next ? prev->next->frame : 0; | |
295 | ||
296 | #ifdef INIT_EXTRA_FRAME_INFO | |
297 | INIT_EXTRA_FRAME_INFO(prev); | |
298 | #endif | |
299 | ||
300 | /* This entry is in the frame queue now, which is good since | |
301 | FRAME_SAVED_PC may use that queue to figure out it's value | |
302 | (see m-sparc.h). We want the pc saved in the inferior frame. */ | |
303 | INIT_FRAME_PC(fromleaf, prev); | |
304 | ||
305 | return prev; | |
306 | } | |
307 | ||
308 | CORE_ADDR | |
309 | get_frame_pc (frame) | |
310 | FRAME frame; | |
311 | { | |
312 | struct frame_info *fi; | |
313 | fi = get_frame_info (frame); | |
314 | return fi->pc; | |
315 | } | |
316 | ||
317 | #if defined (FRAME_FIND_SAVED_REGS) | |
318 | /* Find the addresses in which registers are saved in FRAME. */ | |
319 | ||
320 | void | |
321 | get_frame_saved_regs (frame_info_addr, saved_regs_addr) | |
322 | struct frame_info *frame_info_addr; | |
323 | struct frame_saved_regs *saved_regs_addr; | |
324 | { | |
325 | FRAME_FIND_SAVED_REGS (frame_info_addr, *saved_regs_addr); | |
326 | } | |
327 | #endif | |
328 | ||
329 | /* Return the innermost lexical block in execution | |
330 | in a specified stack frame. The frame address is assumed valid. */ | |
331 | ||
332 | struct block * | |
333 | get_frame_block (frame) | |
334 | FRAME frame; | |
335 | { | |
336 | struct frame_info *fi; | |
337 | CORE_ADDR pc; | |
338 | ||
339 | fi = get_frame_info (frame); | |
340 | ||
341 | pc = fi->pc; | |
342 | if (fi->next_frame != 0) | |
343 | /* We are not in the innermost frame. We need to subtract one to | |
344 | get the correct block, in case the call instruction was the | |
345 | last instruction of the block. If there are any machines on | |
346 | which the saved pc does not point to after the call insn, we | |
347 | probably want to make fi->pc point after the call insn anyway. */ | |
348 | --pc; | |
349 | return block_for_pc (pc); | |
350 | } | |
351 | ||
352 | struct block * | |
353 | get_current_block () | |
354 | { | |
355 | return block_for_pc (read_pc ()); | |
356 | } | |
357 | ||
358 | CORE_ADDR | |
359 | get_pc_function_start (pc) | |
360 | CORE_ADDR pc; | |
361 | { | |
362 | register struct block *bl = block_for_pc (pc); | |
363 | register struct symbol *symbol; | |
364 | if (bl == 0 || (symbol = block_function (bl)) == 0) | |
365 | { | |
366 | register int misc_index = find_pc_misc_function (pc); | |
367 | if (misc_index >= 0) | |
368 | return misc_function_vector[misc_index].address; | |
369 | return 0; | |
370 | } | |
371 | bl = SYMBOL_BLOCK_VALUE (symbol); | |
372 | return BLOCK_START (bl); | |
373 | } | |
374 | ||
375 | /* Return the symbol for the function executing in frame FRAME. */ | |
376 | ||
377 | struct symbol * | |
378 | get_frame_function (frame) | |
379 | FRAME frame; | |
380 | { | |
381 | register struct block *bl = get_frame_block (frame); | |
382 | if (bl == 0) | |
383 | return 0; | |
384 | return block_function (bl); | |
385 | } | |
386 | \f | |
387 | /* Return the blockvector immediately containing the innermost lexical block | |
388 | containing the specified pc value, or 0 if there is none. | |
389 | PINDEX is a pointer to the index value of the block. If PINDEX | |
390 | is NULL, we don't pass this information back to the caller. */ | |
391 | ||
392 | struct blockvector * | |
393 | blockvector_for_pc (pc, pindex) | |
394 | register CORE_ADDR pc; | |
395 | int *pindex; | |
396 | { | |
397 | register struct block *b; | |
398 | register int bot, top, half; | |
399 | register struct symtab *s; | |
400 | struct blockvector *bl; | |
401 | ||
402 | /* First search all symtabs for one whose file contains our pc */ | |
403 | s = find_pc_symtab (pc); | |
404 | if (s == 0) | |
405 | return 0; | |
406 | ||
407 | bl = BLOCKVECTOR (s); | |
408 | b = BLOCKVECTOR_BLOCK (bl, 0); | |
409 | ||
410 | /* Then search that symtab for the smallest block that wins. */ | |
411 | /* Use binary search to find the last block that starts before PC. */ | |
412 | ||
413 | bot = 0; | |
414 | top = BLOCKVECTOR_NBLOCKS (bl); | |
415 | ||
416 | while (top - bot > 1) | |
417 | { | |
418 | half = (top - bot + 1) >> 1; | |
419 | b = BLOCKVECTOR_BLOCK (bl, bot + half); | |
420 | if (BLOCK_START (b) <= pc) | |
421 | bot += half; | |
422 | else | |
423 | top = bot + half; | |
424 | } | |
425 | ||
426 | /* Now search backward for a block that ends after PC. */ | |
427 | ||
428 | while (bot >= 0) | |
429 | { | |
430 | b = BLOCKVECTOR_BLOCK (bl, bot); | |
431 | if (BLOCK_END (b) > pc) | |
432 | { | |
433 | if (pindex) | |
434 | *pindex = bot; | |
435 | return bl; | |
436 | } | |
437 | bot--; | |
438 | } | |
439 | ||
440 | return 0; | |
441 | } | |
442 | ||
443 | /* Return the innermost lexical block containing the specified pc value, | |
444 | or 0 if there is none. */ | |
445 | ||
446 | struct block * | |
447 | block_for_pc (pc) | |
448 | register CORE_ADDR pc; | |
449 | { | |
450 | register struct blockvector *bl; | |
451 | int index; | |
452 | ||
453 | bl = blockvector_for_pc (pc, &index); | |
454 | if (bl) | |
455 | return BLOCKVECTOR_BLOCK (bl, index); | |
456 | return 0; | |
457 | } | |
458 | ||
459 | /* Return the function containing pc value PC. | |
460 | Returns 0 if function is not known. */ | |
461 | ||
462 | struct symbol * | |
463 | find_pc_function (pc) | |
464 | CORE_ADDR pc; | |
465 | { | |
466 | register struct block *b = block_for_pc (pc); | |
467 | if (b == 0) | |
468 | return 0; | |
469 | return block_function (b); | |
470 | } | |
471 | ||
472 | /* These variables are used to cache the most recent result | |
473 | * of find_pc_partial_function. */ | |
474 | ||
475 | static CORE_ADDR cache_pc_function_low = 0; | |
476 | static CORE_ADDR cache_pc_function_high = 0; | |
477 | static char *cache_pc_function_name = 0; | |
478 | ||
479 | /* Clear cache, e.g. when symbol table is discarded. */ | |
480 | ||
481 | void | |
482 | clear_pc_function_cache() | |
483 | { | |
484 | cache_pc_function_low = 0; | |
485 | cache_pc_function_high = 0; | |
486 | cache_pc_function_name = (char *)0; | |
487 | } | |
488 | ||
489 | /* Finds the "function" (text symbol) that is smaller than PC | |
490 | but greatest of all of the potential text symbols. Sets | |
491 | *NAME and/or *ADDRESS conditionally if that pointer is non-zero. | |
492 | Returns 0 if it couldn't find anything, 1 if it did. On a zero | |
493 | return, *NAME and *ADDRESS are always set to zero. On a 1 return, | |
494 | *NAME and *ADDRESS contain real information. */ | |
495 | ||
496 | int | |
497 | find_pc_partial_function (pc, name, address) | |
498 | CORE_ADDR pc; | |
499 | char **name; | |
500 | CORE_ADDR *address; | |
501 | { | |
502 | struct partial_symtab *pst; | |
503 | struct symbol *f; | |
504 | int miscfunc; | |
505 | struct partial_symbol *psb; | |
506 | ||
507 | if (pc >= cache_pc_function_low && pc < cache_pc_function_high) | |
508 | { | |
509 | if (address) | |
510 | *address = cache_pc_function_low; | |
511 | if (name) | |
512 | *name = cache_pc_function_name; | |
513 | return 1; | |
514 | } | |
515 | ||
516 | pst = find_pc_psymtab (pc); | |
517 | if (pst) | |
518 | { | |
519 | if (pst->readin) | |
520 | { | |
521 | /* The information we want has already been read in. | |
522 | We can go to the already readin symbols and we'll get | |
523 | the best possible answer. */ | |
524 | f = find_pc_function (pc); | |
525 | if (!f) | |
526 | { | |
527 | return_error: | |
528 | /* No available symbol. */ | |
529 | if (name != 0) | |
530 | *name = 0; | |
531 | if (address != 0) | |
532 | *address = 0; | |
533 | return 0; | |
534 | } | |
535 | ||
536 | cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f)); | |
537 | cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f)); | |
538 | cache_pc_function_name = SYMBOL_NAME (f); | |
539 | if (name) | |
540 | *name = cache_pc_function_name; | |
541 | if (address) | |
542 | *address = cache_pc_function_low; | |
543 | return 1; | |
544 | } | |
545 | ||
546 | /* Get the information from a combination of the pst | |
547 | (static symbols), and the misc function vector (extern | |
548 | symbols). */ | |
549 | miscfunc = find_pc_misc_function (pc); | |
550 | psb = find_pc_psymbol (pst, pc); | |
551 | ||
552 | if (!psb && miscfunc == -1) | |
553 | { | |
554 | goto return_error; | |
555 | } | |
556 | if (psb | |
557 | && (miscfunc == -1 | |
558 | || (SYMBOL_VALUE_ADDRESS (psb) | |
559 | >= misc_function_vector[miscfunc].address))) | |
560 | { | |
561 | /* This case isn't being cached currently. */ | |
562 | if (address) | |
563 | *address = SYMBOL_VALUE_ADDRESS (psb); | |
564 | if (name) | |
565 | *name = SYMBOL_NAME (psb); | |
566 | return 1; | |
567 | } | |
568 | } | |
569 | else | |
570 | /* Must be in the misc function stuff. */ | |
571 | { | |
572 | miscfunc = find_pc_misc_function (pc); | |
573 | if (miscfunc == -1) | |
574 | goto return_error; | |
575 | } | |
576 | ||
577 | { | |
578 | if (misc_function_vector[miscfunc].type == mf_text) | |
579 | cache_pc_function_low = misc_function_vector[miscfunc].address; | |
580 | else | |
581 | /* It is a transfer table for Sun shared libraries. */ | |
582 | cache_pc_function_low = pc - FUNCTION_START_OFFSET; | |
583 | } | |
584 | cache_pc_function_name = misc_function_vector[miscfunc].name; | |
d11c44f1 | 585 | if (miscfunc < misc_function_count /* && FIXME mf_text again? */ ) |
bd5635a1 RP |
586 | cache_pc_function_high = misc_function_vector[miscfunc+1].address; |
587 | else | |
588 | cache_pc_function_high = cache_pc_function_low + 1; | |
589 | if (address) | |
590 | *address = cache_pc_function_low; | |
591 | if (name) | |
592 | *name = cache_pc_function_name; | |
593 | return 1; | |
594 | } | |
595 | ||
596 | /* Find the misc function whose address is the largest | |
597 | while being less than PC. Return its index in misc_function_vector. | |
598 | Returns -1 if PC is not in suitable range. */ | |
599 | ||
600 | int | |
601 | find_pc_misc_function (pc) | |
602 | register CORE_ADDR pc; | |
603 | { | |
604 | register int lo = 0; | |
605 | register int hi = misc_function_count-1; | |
606 | register int new; | |
607 | ||
608 | /* Note that the last thing in the vector is always _etext. */ | |
609 | /* Actually, "end", now that non-functions | |
610 | go on the misc_function_vector. */ | |
611 | ||
612 | /* Above statement is not *always* true - fix for case where there are */ | |
613 | /* no misc functions at all (ie no symbol table has been read). */ | |
614 | if (hi < 0) return -1; /* no misc functions recorded */ | |
615 | ||
616 | /* trivial reject range test */ | |
617 | if (pc < misc_function_vector[0].address || | |
618 | pc > misc_function_vector[hi].address) | |
619 | return -1; | |
620 | ||
621 | /* Note that the following search will not return hi if | |
622 | pc == misc_function_vector[hi].address. If "end" points to the | |
623 | first unused location, this is correct and the above test | |
624 | simply needs to be changed to | |
625 | "pc >= misc_function_vector[hi].address". */ | |
626 | do { | |
627 | new = (lo + hi) >> 1; | |
628 | if (misc_function_vector[new].address == pc) | |
629 | return new; /* an exact match */ | |
630 | else if (misc_function_vector[new].address > pc) | |
631 | hi = new; | |
632 | else | |
633 | lo = new; | |
634 | } while (hi-lo != 1); | |
635 | ||
636 | /* if here, we had no exact match, so return the lower choice */ | |
637 | return lo; | |
638 | } | |
639 | ||
640 | /* Return the innermost stack frame executing inside of the specified block, | |
641 | or zero if there is no such frame. */ | |
642 | ||
643 | FRAME | |
644 | block_innermost_frame (block) | |
645 | struct block *block; | |
646 | { | |
647 | struct frame_info *fi; | |
648 | register FRAME frame; | |
649 | register CORE_ADDR start = BLOCK_START (block); | |
650 | register CORE_ADDR end = BLOCK_END (block); | |
651 | ||
652 | frame = 0; | |
653 | while (1) | |
654 | { | |
655 | frame = get_prev_frame (frame); | |
656 | if (frame == 0) | |
657 | return 0; | |
658 | fi = get_frame_info (frame); | |
659 | if (fi->pc >= start && fi->pc < end) | |
660 | return frame; | |
661 | } | |
662 | } | |
663 | ||
664 | void | |
665 | _initialize_blockframe () | |
666 | { | |
667 | obstack_init (&frame_cache_obstack); | |
668 | } |