|
8 | 8 | "cmd/internal/dwarf"
|
9 | 9 | "cmd/internal/obj"
|
10 | 10 | "cmd/internal/src"
|
| 11 | + "fmt" |
11 | 12 | "strings"
|
12 | 13 | )
|
13 | 14 |
|
@@ -170,12 +171,32 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls {
|
170 | 171 | addRange(inlcalls.Calls, start, fnsym.Size, curii, imap)
|
171 | 172 | }
|
172 | 173 |
|
| 174 | + // Issue 33188: if II foo is a child of II bar, then ensure that |
| 175 | + // bar's ranges include the ranges of foo (the loop above will produce |
| 176 | + // disjoint ranges). |
| 177 | + for k, c := range inlcalls.Calls { |
| 178 | + if c.Root { |
| 179 | + unifyCallRanges(inlcalls, k) |
| 180 | + } |
| 181 | + } |
| 182 | + |
173 | 183 | // Debugging
|
174 | 184 | if Debug_gendwarfinl != 0 {
|
175 | 185 | dumpInlCalls(inlcalls)
|
176 | 186 | dumpInlVars(dwVars)
|
177 | 187 | }
|
178 | 188 |
|
| 189 | + // Perform a consistency check on inlined routine PC ranges |
| 190 | + // produced by unifyCallRanges above. In particular, complain in |
| 191 | + // cases where you have A -> B -> C (e.g. C is inlined into B, and |
| 192 | + // B is inlined into A) and the ranges for B are not enclosed |
| 193 | + // within the ranges for A, or C within B. |
| 194 | + for k, c := range inlcalls.Calls { |
| 195 | + if c.Root { |
| 196 | + checkInlCall(fnsym.Name, inlcalls, fnsym.Size, k, -1) |
| 197 | + } |
| 198 | + } |
| 199 | + |
179 | 200 | return inlcalls
|
180 | 201 | }
|
181 | 202 |
|
@@ -355,3 +376,74 @@ func dumpInlVars(dwvars []*dwarf.Var) {
|
355 | 376 | Ctxt.Logf("V%d: %s CI:%d II:%d IA:%d %s\n", i, dwv.Name, dwv.ChildIndex, dwv.InlIndex-1, ia, typ)
|
356 | 377 | }
|
357 | 378 | }
|
| 379 | + |
| 380 | +func rangesContains(par []dwarf.Range, rng dwarf.Range) (bool, string) { |
| 381 | + for _, r := range par { |
| 382 | + if rng.Start >= r.Start && rng.End <= r.End { |
| 383 | + return true, "" |
| 384 | + } |
| 385 | + } |
| 386 | + msg := fmt.Sprintf("range [%d,%d) not contained in {", rng.Start, rng.End) |
| 387 | + for _, r := range par { |
| 388 | + msg += fmt.Sprintf(" [%d,%d)", r.Start, r.End) |
| 389 | + } |
| 390 | + msg += " }" |
| 391 | + return false, msg |
| 392 | +} |
| 393 | + |
| 394 | +func rangesContainsAll(parent, child []dwarf.Range) (bool, string) { |
| 395 | + for _, r := range child { |
| 396 | + c, m := rangesContains(parent, r) |
| 397 | + if !c { |
| 398 | + return false, m |
| 399 | + } |
| 400 | + } |
| 401 | + return true, "" |
| 402 | +} |
| 403 | + |
| 404 | +// checkInlCall verifies that the PC ranges for inline info 'idx' are |
| 405 | +// enclosed/contained within the ranges of its parent inline (or if |
| 406 | +// this is a root/toplevel inline, checks that the ranges fall within |
| 407 | +// the extent of the top level function). A panic is issued if a |
| 408 | +// malformed range is found. |
| 409 | +func checkInlCall(funcName string, inlCalls dwarf.InlCalls, funcSize int64, idx, parentIdx int) { |
| 410 | + |
| 411 | + // Callee |
| 412 | + ic := inlCalls.Calls[idx] |
| 413 | + callee := Ctxt.InlTree.InlinedFunction(ic.InlIndex).Name |
| 414 | + calleeRanges := ic.Ranges |
| 415 | + |
| 416 | + // Caller |
| 417 | + caller := funcName |
| 418 | + parentRanges := []dwarf.Range{dwarf.Range{Start: int64(0), End: funcSize}} |
| 419 | + if parentIdx != -1 { |
| 420 | + pic := inlCalls.Calls[parentIdx] |
| 421 | + caller = Ctxt.InlTree.InlinedFunction(pic.InlIndex).Name |
| 422 | + parentRanges = pic.Ranges |
| 423 | + } |
| 424 | + |
| 425 | + // Callee ranges contained in caller ranges? |
| 426 | + c, m := rangesContainsAll(parentRanges, calleeRanges) |
| 427 | + if !c { |
| 428 | + Fatalf("** malformed inlined routine range in %s: caller %s callee %s II=%d %s\n", funcName, caller, callee, idx, m) |
| 429 | + } |
| 430 | + |
| 431 | + // Now visit kids |
| 432 | + for _, k := range ic.Children { |
| 433 | + checkInlCall(funcName, inlCalls, funcSize, k, idx) |
| 434 | + } |
| 435 | +} |
| 436 | + |
| 437 | +// unifyCallRanges ensures that the ranges for a given inline |
| 438 | +// transitively include all of the ranges for its child inlines. |
| 439 | +func unifyCallRanges(inlcalls dwarf.InlCalls, idx int) { |
| 440 | + ic := &inlcalls.Calls[idx] |
| 441 | + for _, childIdx := range ic.Children { |
| 442 | + // First make sure child ranges are unified. |
| 443 | + unifyCallRanges(inlcalls, childIdx) |
| 444 | + |
| 445 | + // Then merge child ranges into ranges for this inline. |
| 446 | + cic := inlcalls.Calls[childIdx] |
| 447 | + ic.Ranges = dwarf.MergeRanges(ic.Ranges, cic.Ranges) |
| 448 | + } |
| 449 | +} |
0 commit comments