GNU Binutils with patches for OS216
修訂 | 83b9557361c2d79479e17d5967f5180c371fa138 (tree) |
---|---|
時間 | 2017-11-29 05:39:19 |
作者 | Keith Seitz <keiths@redh...> |
Commiter | Keith Seitz |
Report stop locations in inlined functions
This is a patch for a very related inline function problem. Using the
test case from breakpoints/17534,
3 static inline void NVIC_EnableIRQ(int IRQn)
4 {
5 volatile int y;
6 y = IRQn;
7 }
8
9 attribute( ( always_inline ) ) static inline void WFI(void)
10 {
11 asm volatile ("nop");
12 }
13
14 int main(void) {
15
16 x= 42;
17
18 if (x)
19 NVIC_EnableIRQ(16);
20 else
21 NVIC_EnableIRQ(18);
(gdb) b NVIC_EnableIRQ
Breakpoint 1 at 0x4003e4: NVIC_EnableIRQ. (2 locations)
(gdb) r
Starting program: 17534
Breakpoint 1, main () at 17534.c:19
19 NVIC_EnableIRQ(16);
This happens because skip_inline_frames automatically skips every inlined
frame. Based on a suggestion by Jan, this patch introduces a new function,
breakpoint_for_stop, which attempts to ascertain which breakpoint, if any,
caused a particular stop in the inferior. That breakpoint is then passed
to skip_inline_frames so that it can decide if a particular inlined frame
should be skipped.
I've had to separate the bpstat chain building from bpstat_stop_status --
py-finish-breakpoint.exp did not like me calling bpstat_stop_status multiple
times. So I've added the ability to allocate the chain separately and
optionally pass it to bpstat_stop_status, which remains otherwise unchanged.
With this patch, GDB now correctly reports that the inferior has stopped
inside the inlined function:
(gdb) r
Starting program: 17534
Breakpoint 1, NVIC_EnableIRQ (IRQn=16) at 17534.c:6
6 y = IRQn;
gdb/ChangeLog:
* breakpoint.c (bpstat_explains_signal): Add output parameter for
breakpoint and save the breakpoint if one is found to explain
the signal.
All callers updated.
(build_bpstat_chain): New function, moved from bpstat_stop_status.
(breakpoint_for_stop): New function.
(bpstat_stop_status): Add new optional parameter for the bpstat chain.
If this new parameter is NULL, call build_bpstat_chain.
All callers updated.
* breakpoint.h (breakpoint_for_stop): Declare.
(bpstat_explains_signal): Update declaration.
* infrun.c (handle_signal_stop): Before calling skip_inline_frames,
use breakpoint_for_stop to find the breakpoint that caused us
to stop.
Save the bpstat chain for later invocation of bpstat_stop_status.
* inline-frame.c: Include linespec.h.
(skip_inline_frames): Add struct breakpoint parameter.
Re-parse the location of the breakpoint causing the stop, if any,
and only skip frames that did not cause the stop.
* inline-frame.h (skip_inline_frames): Update declaration.
gdb/testsuite/ChangeLog:
* gdb.opt/inline-break.c (inline_func1, not_inline_func1)
(inline_func2, not_inline_func2, inline_func3, not_inline_func3):
New functions.
(main): Call not_inline_func3.
* gdb.opt/inline-break.exp: Start inferior and set breakpoints at
inline_func1, inline_func2, and inline_func3. Test that when each
breakpoint is hit, GDB properly reports both the stop location
and the backtrace.
@@ -5357,58 +5357,25 @@ need_moribund_for_location_type (struct bp_location *loc) | ||
5357 | 5357 | && !target_supports_stopped_by_hw_breakpoint ())); |
5358 | 5358 | } |
5359 | 5359 | |
5360 | - | |
5361 | -/* Get a bpstat associated with having just stopped at address | |
5362 | - BP_ADDR in thread PTID. | |
5363 | - | |
5364 | - Determine whether we stopped at a breakpoint, etc, or whether we | |
5365 | - don't understand this stop. Result is a chain of bpstat's such | |
5366 | - that: | |
5367 | - | |
5368 | - if we don't understand the stop, the result is a null pointer. | |
5369 | - | |
5370 | - if we understand why we stopped, the result is not null. | |
5371 | - | |
5372 | - Each element of the chain refers to a particular breakpoint or | |
5373 | - watchpoint at which we have stopped. (We may have stopped for | |
5374 | - several reasons concurrently.) | |
5375 | - | |
5376 | - Each element of the chain has valid next, breakpoint_at, | |
5377 | - commands, FIXME??? fields. */ | |
5360 | +/* See breakpoint.h. */ | |
5378 | 5361 | |
5379 | 5362 | bpstat |
5380 | -bpstat_stop_status (const address_space *aspace, | |
5381 | - CORE_ADDR bp_addr, ptid_t ptid, | |
5363 | +build_bpstat_chain (const address_space *aspace, CORE_ADDR bp_addr, | |
5382 | 5364 | const struct target_waitstatus *ws) |
5383 | 5365 | { |
5384 | - struct breakpoint *b = NULL; | |
5385 | - struct bp_location *bl; | |
5386 | - struct bp_location *loc; | |
5387 | - /* First item of allocated bpstat's. */ | |
5366 | + struct breakpoint *b; | |
5388 | 5367 | bpstat bs_head = NULL, *bs_link = &bs_head; |
5389 | - /* Pointer to the last thing in the chain currently. */ | |
5390 | - bpstat bs; | |
5391 | - int ix; | |
5392 | - int need_remove_insert; | |
5393 | - int removed_any; | |
5394 | - | |
5395 | - /* First, build the bpstat chain with locations that explain a | |
5396 | - target stop, while being careful to not set the target running, | |
5397 | - as that may invalidate locations (in particular watchpoint | |
5398 | - locations are recreated). Resuming will happen here with | |
5399 | - breakpoint conditions or watchpoint expressions that include | |
5400 | - inferior function calls. */ | |
5401 | 5368 | |
5402 | 5369 | ALL_BREAKPOINTS (b) |
5403 | 5370 | { |
5404 | 5371 | if (!breakpoint_enabled (b)) |
5405 | 5372 | continue; |
5406 | 5373 | |
5407 | - for (bl = b->loc; bl != NULL; bl = bl->next) | |
5374 | + for (bp_location *bl = b->loc; bl != NULL; bl = bl->next) | |
5408 | 5375 | { |
5409 | 5376 | /* For hardware watchpoints, we look only at the first |
5410 | 5377 | location. The watchpoint_check function will work on the |
5411 | - entire expression, not the individual locations. For | |
5378 | + | |
5412 | 5379 | read watchpoints, the watchpoints_triggered function has |
5413 | 5380 | checked all locations already. */ |
5414 | 5381 | if (b->type == bp_hardware_watchpoint && bl != b->loc) |
@@ -5423,8 +5390,8 @@ bpstat_stop_status (const address_space *aspace, | ||
5423 | 5390 | /* Come here if it's a watchpoint, or if the break address |
5424 | 5391 | matches. */ |
5425 | 5392 | |
5426 | - bs = new bpstats (bl, &bs_link); /* Alloc a bpstat to | |
5427 | - explain stop. */ | |
5393 | + bpstat bs = new bpstats (bl, &bs_link); /* Alloc a bpstat to | |
5394 | + explain stop. */ | |
5428 | 5395 | |
5429 | 5396 | /* Assume we stop. Should we find a watchpoint that is not |
5430 | 5397 | actually triggered, or if the condition of the breakpoint |
@@ -5449,12 +5416,15 @@ bpstat_stop_status (const address_space *aspace, | ||
5449 | 5416 | if (!target_supports_stopped_by_sw_breakpoint () |
5450 | 5417 | || !target_supports_stopped_by_hw_breakpoint ()) |
5451 | 5418 | { |
5452 | - for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix) | |
5419 | + struct bp_location *loc; | |
5420 | + | |
5421 | + for (int ix = 0; | |
5422 | + VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix) | |
5453 | 5423 | { |
5454 | 5424 | if (breakpoint_location_address_match (loc, aspace, bp_addr) |
5455 | 5425 | && need_moribund_for_location_type (loc)) |
5456 | 5426 | { |
5457 | - bs = new bpstats (loc, &bs_link); | |
5427 | + bpstat bs = new bpstats (loc, &bs_link); | |
5458 | 5428 | /* For hits of moribund locations, we should just proceed. */ |
5459 | 5429 | bs->stop = 0; |
5460 | 5430 | bs->print = 0; |
@@ -5463,6 +5433,49 @@ bpstat_stop_status (const address_space *aspace, | ||
5463 | 5433 | } |
5464 | 5434 | } |
5465 | 5435 | |
5436 | + return bs_head; | |
5437 | +} | |
5438 | + | |
5439 | +/* Get a bpstat associated with having just stopped at address | |
5440 | + BP_ADDR in thread PTID. | |
5441 | + | |
5442 | + Determine whether we stopped at a breakpoint, etc, or whether we | |
5443 | + don't understand this stop. Result is a chain of bpstat's such | |
5444 | + that: | |
5445 | + | |
5446 | + if we don't understand the stop, the result is a null pointer. | |
5447 | + | |
5448 | + if we understand why we stopped, the result is not null. | |
5449 | + | |
5450 | + Each element of the chain refers to a particular breakpoint or | |
5451 | + watchpoint at which we have stopped. (We may have stopped for | |
5452 | + several reasons concurrently.) | |
5453 | + | |
5454 | + Each element of the chain has valid next, breakpoint_at, | |
5455 | + commands, FIXME??? fields. */ | |
5456 | + | |
5457 | +bpstat | |
5458 | +bpstat_stop_status (const address_space *aspace, | |
5459 | + CORE_ADDR bp_addr, ptid_t ptid, | |
5460 | + const struct target_waitstatus *ws, | |
5461 | + bpstat stop_chain) | |
5462 | +{ | |
5463 | + struct breakpoint *b = NULL; | |
5464 | + /* First item of allocated bpstat's. */ | |
5465 | + bpstat bs_head = stop_chain; | |
5466 | + bpstat bs; | |
5467 | + int need_remove_insert; | |
5468 | + int removed_any; | |
5469 | + | |
5470 | + /* First, build the bpstat chain with locations that explain a | |
5471 | + target stop, while being careful to not set the target running, | |
5472 | + as that may invalidate locations (in particular watchpoint | |
5473 | + locations are recreated). Resuming will happen here with | |
5474 | + breakpoint conditions or watchpoint expressions that include | |
5475 | + inferior function calls. */ | |
5476 | + if (bs_head == NULL) | |
5477 | + bs_head = build_bpstat_chain (aspace, bp_addr, ws); | |
5478 | + | |
5466 | 5479 | /* A bit of special processing for shlib breakpoints. We need to |
5467 | 5480 | process solib loading here, so that the lists of loaded and |
5468 | 5481 | unloaded libraries are correct before we handle "catch load" and |
@@ -6780,22 +6793,9 @@ describe_other_breakpoints (struct gdbarch *gdbarch, | ||
6780 | 6793 | } |
6781 | 6794 | |
6782 | 6795 | |
6783 | -/* Return true iff it is meaningful to use the address member of | |
6784 | - BPT locations. For some breakpoint types, the locations' address members | |
6785 | - are irrelevant and it makes no sense to attempt to compare them to other | |
6786 | - addresses (or use them for any other purpose either). | |
6787 | - | |
6788 | - More specifically, each of the following breakpoint types will | |
6789 | - always have a zero valued location address and we don't want to mark | |
6790 | - breakpoints of any of these types to be a duplicate of an actual | |
6791 | - breakpoint location at address zero: | |
6792 | - | |
6793 | - bp_watchpoint | |
6794 | - bp_catchpoint | |
6795 | - | |
6796 | -*/ | |
6796 | +/* See breakpoint.h. */ | |
6797 | 6797 | |
6798 | -static int | |
6798 | +bool | |
6799 | 6799 | breakpoint_address_is_meaningful (struct breakpoint *bpt) |
6800 | 6800 | { |
6801 | 6801 | enum bptype type = bpt->type; |
@@ -917,9 +917,35 @@ extern void bpstat_clear (bpstat *); | ||
917 | 917 | is part of the bpstat is copied as well. */ |
918 | 918 | extern bpstat bpstat_copy (bpstat); |
919 | 919 | |
920 | +/* Build the bstat chain for the stop information given by ASPACE, | |
921 | + BP_ADDR, and WS. Returns the head of the bpstat chain. */ | |
922 | + | |
923 | +extern bpstat build_bpstat_chain (const address_space *aspace, | |
924 | + CORE_ADDR bp_addr, | |
925 | + const struct target_waitstatus *ws); | |
926 | + | |
920 | 927 | extern bpstat bpstat_stop_status (const address_space *aspace, |
921 | 928 | CORE_ADDR pc, ptid_t ptid, |
922 | - const struct target_waitstatus *ws); | |
929 | + const struct target_waitstatus *ws, | |
930 | + bpstat stop_chain = NULL); | |
931 | + | |
932 | +/* Return true iff it is meaningful to use the address member of | |
933 | + BPT locations. For some breakpoint types, the locations' address members | |
934 | + are irrelevant and it makes no sense to attempt to compare them to other | |
935 | + addresses (or use them for any other purpose either). | |
936 | + | |
937 | + More specifically, each of the following breakpoint types will | |
938 | + always have a zero valued location address and we don't want to mark | |
939 | + breakpoints of any of these types to be a duplicate of an actual | |
940 | + breakpoint location at address zero: | |
941 | + | |
942 | + bp_watchpoint | |
943 | + bp_catchpoint | |
944 | + | |
945 | +*/ | |
946 | + | |
947 | +extern bool breakpoint_address_is_meaningful (struct breakpoint *bpt); | |
948 | + | |
923 | 949 | |
924 | 950 | /* This bpstat_what stuff tells wait_for_inferior what to do with a |
925 | 951 | breakpoint (a challenging task). |
@@ -5839,6 +5839,7 @@ handle_signal_stop (struct execution_control_state *ecs) | ||
5839 | 5839 | ecs->event_thread->control.stop_step = 0; |
5840 | 5840 | stop_print_frame = 1; |
5841 | 5841 | stopped_by_random_signal = 0; |
5842 | + bpstat stop_chain = NULL; | |
5842 | 5843 | |
5843 | 5844 | /* Hide inlined functions starting here, unless we just performed stepi or |
5844 | 5845 | nexti. After stepi and nexti, always show the innermost frame (not any |
@@ -5870,7 +5871,13 @@ handle_signal_stop (struct execution_control_state *ecs) | ||
5870 | 5871 | ecs->event_thread->prev_pc, |
5871 | 5872 | &ecs->ws))) |
5872 | 5873 | { |
5873 | - skip_inline_frames (ecs->ptid); | |
5874 | + struct breakpoint *bpt = NULL; | |
5875 | + | |
5876 | + stop_chain = build_bpstat_chain (aspace, stop_pc, &ecs->ws); | |
5877 | + if (stop_chain != NULL) | |
5878 | + bpt = stop_chain->breakpoint_at; | |
5879 | + | |
5880 | + skip_inline_frames (ecs->ptid, bpt); | |
5874 | 5881 | |
5875 | 5882 | /* Re-fetch current thread's frame in case that invalidated |
5876 | 5883 | the frame cache. */ |
@@ -5919,7 +5926,7 @@ handle_signal_stop (struct execution_control_state *ecs) | ||
5919 | 5926 | handles this event. */ |
5920 | 5927 | ecs->event_thread->control.stop_bpstat |
5921 | 5928 | = bpstat_stop_status (get_current_regcache ()->aspace (), |
5922 | - stop_pc, ecs->ptid, &ecs->ws); | |
5929 | + stop_pc, ecs->ptid, &ecs->ws, stop_chain); | |
5923 | 5930 | |
5924 | 5931 | /* Following in case break condition called a |
5925 | 5932 | function. */ |
@@ -301,7 +301,7 @@ block_starting_point_at (CORE_ADDR pc, const struct block *block) | ||
301 | 301 | user steps into them. */ |
302 | 302 | |
303 | 303 | void |
304 | -skip_inline_frames (ptid_t ptid) | |
304 | +skip_inline_frames (ptid_t ptid, struct breakpoint *bpt) | |
305 | 305 | { |
306 | 306 | CORE_ADDR this_pc; |
307 | 307 | const struct block *frame_block, *cur_block; |
@@ -327,7 +327,25 @@ skip_inline_frames (ptid_t ptid) | ||
327 | 327 | if (BLOCK_START (cur_block) == this_pc |
328 | 328 | || block_starting_point_at (this_pc, cur_block)) |
329 | 329 | { |
330 | - skip_count++; | |
330 | + bool skip_this_frame = true; | |
331 | + | |
332 | + if (bpt != NULL | |
333 | + && user_breakpoint_p (bpt) | |
334 | + && breakpoint_address_is_meaningful (bpt)) | |
335 | + { | |
336 | + for (bp_location *loc = bpt->loc; loc != NULL; | |
337 | + loc = loc->next) | |
338 | + { | |
339 | + if (loc->address == this_pc) | |
340 | + { | |
341 | + skip_this_frame = false; | |
342 | + break; | |
343 | + } | |
344 | + } | |
345 | + } | |
346 | + | |
347 | + if (skip_this_frame) | |
348 | + skip_count++; | |
331 | 349 | last_sym = BLOCK_FUNCTION (cur_block); |
332 | 350 | } |
333 | 351 | else |
@@ -31,7 +31,7 @@ extern const struct frame_unwind inline_frame_unwind; | ||
31 | 31 | Frames for the hidden functions will not appear in the backtrace until the |
32 | 32 | user steps into them. */ |
33 | 33 | |
34 | -void skip_inline_frames (ptid_t ptid); | |
34 | +void skip_inline_frames (ptid_t ptid, struct breakpoint *bpt); | |
35 | 35 | |
36 | 36 | /* Forget about any hidden inlined functions in PTID, which is new or |
37 | 37 | about to be resumed. If PTID is minus_one_ptid, forget about all |
@@ -128,6 +128,54 @@ func8a (int x) | ||
128 | 128 | return func8b (x * 31); |
129 | 129 | } |
130 | 130 | |
131 | +static inline ATTR int | |
132 | +inline_func1 (int x) | |
133 | +{ | |
134 | + int y = 1; /* inline_func1 */ | |
135 | + | |
136 | + return y + x; | |
137 | +} | |
138 | + | |
139 | +static int | |
140 | +not_inline_func1 (int x) | |
141 | +{ | |
142 | + int y = 2; /* not_inline_func1 */ | |
143 | + | |
144 | + return y + inline_func1 (x); | |
145 | +} | |
146 | + | |
147 | +inline ATTR int | |
148 | +inline_func2 (int x) | |
149 | +{ | |
150 | + int y = 3; /* inline_func2 */ | |
151 | + | |
152 | + return y + not_inline_func1 (x); | |
153 | +} | |
154 | + | |
155 | +int | |
156 | +not_inline_func2 (int x) | |
157 | +{ | |
158 | + int y = 4; /* not_inline_func2 */ | |
159 | + | |
160 | + return y + inline_func2 (x); | |
161 | +} | |
162 | + | |
163 | +static inline ATTR int | |
164 | +inline_func3 (int x) | |
165 | +{ | |
166 | + int y = 5; /* inline_func3 */ | |
167 | + | |
168 | + return y + not_inline_func2 (x); | |
169 | +} | |
170 | + | |
171 | +static int | |
172 | +not_inline_func3 (int x) | |
173 | +{ | |
174 | + int y = 6; /* not_inline_func3 */ | |
175 | + | |
176 | + return y + inline_func3 (x); | |
177 | +} | |
178 | + | |
131 | 179 | /* Entry point. */ |
132 | 180 | |
133 | 181 | int |
@@ -155,5 +203,7 @@ main (int argc, char *argv[]) | ||
155 | 203 | |
156 | 204 | x = func8a (x) + func8b (x); |
157 | 205 | |
206 | + x = not_inline_func3 (-21); | |
207 | + | |
158 | 208 | return x; |
159 | 209 | } |
@@ -185,4 +185,39 @@ for {set i 1} {$i <= [array size results]} {incr i} { | ||
185 | 185 | gdb_test "info break $i" $results($i) |
186 | 186 | } |
187 | 187 | |
188 | +# Start us running. | |
189 | +if {![runto main]} { | |
190 | + untested "could not run to main" | |
191 | + return -1 | |
192 | +} | |
193 | + | |
194 | +# Insert breakpoints for all inline_func? and not_inline_func? and check | |
195 | +# that we actually stop where we think we should. | |
196 | + | |
197 | +for {set i 1} {$i < 4} {incr i} { | |
198 | + foreach inline {"not_inline" "inline"} { | |
199 | + gdb_breakpoint "${inline}_func$i" message | |
200 | + } | |
201 | +} | |
202 | + | |
203 | +set ws {[\r\n\t ]+} | |
204 | +set backtrace [list "(in|at)? main"] | |
205 | +for {set i 3} {$i > 0} {incr i -1} { | |
206 | + | |
207 | + foreach inline {"not_inline" "inline"} { | |
208 | + | |
209 | + # Check that we stop at the correct location and print out | |
210 | + # the (possibly) inlined frames. | |
211 | + set num [gdb_get_line_number "/* ${inline}_func$i */"] | |
212 | + set pattern ".*/$srcfile:$num${ws}.*$num${ws}int y = $decimal;" | |
213 | + append pattern "${ws}/\\\* ${inline}_func$i \\\*/" | |
214 | + send_log "Expecting $pattern\n" | |
215 | + gdb_continue_to_breakpoint "${inline}_func$i" $pattern | |
216 | + | |
217 | + # Also check for the correct backtrace. | |
218 | + set backtrace [linsert $backtrace 0 "(in|at)?${ws}${inline}_func$i"] | |
219 | + gdb_test_sequence "bt" "bt stopped in ${inline}_func$i" $backtrace | |
220 | + } | |
221 | +} | |
222 | + | |
188 | 223 | unset -nocomplain results |