stack.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. // Copyright 2015 Marc-Antoine Ruel. All rights reserved.
  2. // Use of this source code is governed under the Apache License, Version 2.0
  3. // that can be found in the LICENSE file.
  4. // Package stack analyzes stack dump of Go processes and simplifies it.
  5. //
  6. // It is mostly useful on servers will large number of identical goroutines,
  7. // making the crash dump harder to read than strictly necessary.
  8. package stack
  9. import (
  10. "fmt"
  11. "math"
  12. "net/url"
  13. "os"
  14. "path/filepath"
  15. "regexp"
  16. "sort"
  17. "strings"
  18. "unicode"
  19. "unicode/utf8"
  20. )
  21. const lockedToThread = "locked to thread"
  22. // These are effectively constants.
  23. var (
  24. // TODO(maruel): Handle corrupted stack cases:
  25. // - missed stack barrier
  26. // - found next stack barrier at 0x123; expected
  27. // - runtime: unexpected return pc for FUNC_NAME called from 0x123
  28. reRoutineHeader = regexp.MustCompile("^goroutine (\\d+) \\[([^\\]]+)\\]\\:\r?\n$")
  29. reMinutes = regexp.MustCompile("^(\\d+) minutes$")
  30. reUnavail = regexp.MustCompile("^(?:\t| +)goroutine running on other thread; stack unavailable")
  31. // See gentraceback() in src/runtime/traceback.go for more information.
  32. // - Sometimes the source file comes up as "<autogenerated>". It is the
  33. // compiler than generated these, not the runtime.
  34. // - The tab may be replaced with spaces when a user copy-paste it, handle
  35. // this transparently.
  36. // - "runtime.gopanic" is explicitly replaced with "panic" by gentraceback().
  37. // - The +0x123 byte offset is printed when frame.pc > _func.entry. _func is
  38. // generated by the linker.
  39. // - The +0x123 byte offset is not included with generated code, e.g. unnamed
  40. // functions "func·006()" which is generally go func() { ... }()
  41. // statements. Since the _func is generated at runtime, it's probably why
  42. // _func.entry is not set.
  43. // - C calls may have fp=0x123 sp=0x123 appended. I think it normally happens
  44. // when a signal is not correctly handled. It is printed with m.throwing>0.
  45. // These are discarded.
  46. // - For cgo, the source file may be "??".
  47. reFile = regexp.MustCompile("^(?:\t| +)(\\?\\?|\\<autogenerated\\>|.+\\.(?:c|go|s))\\:(\\d+)(?:| \\+0x[0-9a-f]+)(?:| fp=0x[0-9a-f]+ sp=0x[0-9a-f]+)\r?\n$")
  48. // Sadly, it doesn't note the goroutine number so we could cascade them per
  49. // parenthood.
  50. reCreated = regexp.MustCompile("^created by (.+)\r?\n$")
  51. reFunc = regexp.MustCompile("^(.+)\\((.*)\\)\r?\n$")
  52. reElided = regexp.MustCompile("^\\.\\.\\.additional frames elided\\.\\.\\.\r?\n$")
  53. )
  54. // Func is a function call.
  55. //
  56. // Go stack traces print a mangled function call, this wrapper unmangle the
  57. // string before printing and adds other filtering methods.
  58. type Func struct {
  59. Raw string
  60. }
  61. // String is the fully qualified function name.
  62. //
  63. // Sadly Go is a bit confused when the package name doesn't match the directory
  64. // containing the source file and will use the directory name instead of the
  65. // real package name.
  66. func (f *Func) String() string {
  67. s, _ := url.QueryUnescape(f.Raw)
  68. return s
  69. }
  70. // Name is the naked function name.
  71. func (f *Func) Name() string {
  72. parts := strings.SplitN(filepath.Base(f.Raw), ".", 2)
  73. if len(parts) == 1 {
  74. return parts[0]
  75. }
  76. return parts[1]
  77. }
  78. // PkgName is the package name for this function reference.
  79. func (f *Func) PkgName() string {
  80. parts := strings.SplitN(filepath.Base(f.Raw), ".", 2)
  81. if len(parts) == 1 {
  82. return ""
  83. }
  84. s, _ := url.QueryUnescape(parts[0])
  85. return s
  86. }
  87. // PkgDotName returns "<package>.<func>" format.
  88. func (f *Func) PkgDotName() string {
  89. parts := strings.SplitN(filepath.Base(f.Raw), ".", 2)
  90. s, _ := url.QueryUnescape(parts[0])
  91. if len(parts) == 1 {
  92. return parts[0]
  93. }
  94. if s != "" || parts[1] != "" {
  95. return s + "." + parts[1]
  96. }
  97. return ""
  98. }
  99. // IsExported returns true if the function is exported.
  100. func (f *Func) IsExported() bool {
  101. name := f.Name()
  102. parts := strings.Split(name, ".")
  103. r, _ := utf8.DecodeRuneInString(parts[len(parts)-1])
  104. if unicode.ToUpper(r) == r {
  105. return true
  106. }
  107. return f.PkgName() == "main" && name == "main"
  108. }
  109. // Arg is an argument on a Call.
  110. type Arg struct {
  111. Value uint64 // Value is the raw value as found in the stack trace
  112. Name string // Name is a pseudo name given to the argument
  113. }
  114. // IsPtr returns true if we guess it's a pointer. It's only a guess, it can be
  115. // easily be confused by a bitmask.
  116. func (a *Arg) IsPtr() bool {
  117. // Assumes all pointers are above 16Mb and positive.
  118. return a.Value > 16*1024*1024 && a.Value < math.MaxInt64
  119. }
  120. func (a *Arg) String() string {
  121. if a.Name != "" {
  122. return a.Name
  123. }
  124. if a.Value == 0 {
  125. return "0"
  126. }
  127. return fmt.Sprintf("0x%x", a.Value)
  128. }
  129. // Args is a series of function call arguments.
  130. type Args struct {
  131. Values []Arg // Values is the arguments as shown on the stack trace. They are mangled via simplification.
  132. Processed []string // Processed is the arguments generated from processing the source files. It can have a length lower than Values.
  133. Elided bool // If set, it means there was a trailing ", ..."
  134. }
  135. func (a *Args) String() string {
  136. var v []string
  137. if len(a.Processed) != 0 {
  138. v = make([]string, 0, len(a.Processed))
  139. for _, item := range a.Processed {
  140. v = append(v, item)
  141. }
  142. } else {
  143. v = make([]string, 0, len(a.Values))
  144. for _, item := range a.Values {
  145. v = append(v, item.String())
  146. }
  147. }
  148. if a.Elided {
  149. v = append(v, "...")
  150. }
  151. return strings.Join(v, ", ")
  152. }
  153. // equal returns true only if both arguments are exactly equal.
  154. func (a *Args) equal(r *Args) bool {
  155. if a.Elided != r.Elided || len(a.Values) != len(r.Values) {
  156. return false
  157. }
  158. for i, l := range a.Values {
  159. if l != r.Values[i] {
  160. return false
  161. }
  162. }
  163. return true
  164. }
  165. // similar returns true if the two Args are equal or almost but not quite
  166. // equal.
  167. func (a *Args) similar(r *Args, similar Similarity) bool {
  168. if a.Elided != r.Elided || len(a.Values) != len(r.Values) {
  169. return false
  170. }
  171. if similar == AnyValue {
  172. return true
  173. }
  174. for i, l := range a.Values {
  175. switch similar {
  176. case ExactFlags, ExactLines:
  177. if l != r.Values[i] {
  178. return false
  179. }
  180. default:
  181. if l.IsPtr() != r.Values[i].IsPtr() || (!l.IsPtr() && l != r.Values[i]) {
  182. return false
  183. }
  184. }
  185. }
  186. return true
  187. }
  188. // merge merges two similar Args, zapping out differences.
  189. func (a *Args) merge(r *Args) Args {
  190. out := Args{
  191. Values: make([]Arg, len(a.Values)),
  192. Elided: a.Elided,
  193. }
  194. for i, l := range a.Values {
  195. if l != r.Values[i] {
  196. out.Values[i].Name = "*"
  197. out.Values[i].Value = l.Value
  198. } else {
  199. out.Values[i] = l
  200. }
  201. }
  202. return out
  203. }
  204. // Call is an item in the stack trace.
  205. type Call struct {
  206. SrcPath string // Full path name of the source file as seen in the trace
  207. LocalSrcPath string // Full path name of the source file as seen in the host.
  208. Line int // Line number
  209. Func Func // Fully qualified function name (encoded).
  210. Args Args // Call arguments
  211. IsStdlib bool // true if it is a Go standard library function. This includes the 'go test' generated main executable.
  212. }
  213. // equal returns true only if both calls are exactly equal.
  214. func (c *Call) equal(r *Call) bool {
  215. return c.SrcPath == r.SrcPath && c.Line == r.Line && c.Func == r.Func && c.Args.equal(&r.Args)
  216. }
  217. // similar returns true if the two Call are equal or almost but not quite
  218. // equal.
  219. func (c *Call) similar(r *Call, similar Similarity) bool {
  220. return c.SrcPath == r.SrcPath && c.Line == r.Line && c.Func == r.Func && c.Args.similar(&r.Args, similar)
  221. }
  222. // merge merges two similar Call, zapping out differences.
  223. func (c *Call) merge(r *Call) Call {
  224. return Call{
  225. SrcPath: c.SrcPath,
  226. Line: c.Line,
  227. Func: c.Func,
  228. Args: c.Args.merge(&r.Args),
  229. LocalSrcPath: c.LocalSrcPath,
  230. IsStdlib: c.IsStdlib,
  231. }
  232. }
  233. // SrcName returns the base file name of the source file.
  234. func (c *Call) SrcName() string {
  235. return filepath.Base(c.SrcPath)
  236. }
  237. // SrcLine returns "source.go:line", including only the base file name.
  238. func (c *Call) SrcLine() string {
  239. return fmt.Sprintf("%s:%d", c.SrcName(), c.Line)
  240. }
  241. // FullSrcLine returns "/path/to/source.go:line".
  242. //
  243. // This file path is mutated to look like the local path.
  244. func (c *Call) FullSrcLine() string {
  245. return fmt.Sprintf("%s:%d", c.SrcPath, c.Line)
  246. }
  247. // PkgSrc is one directory plus the file name of the source file.
  248. func (c *Call) PkgSrc() string {
  249. return filepath.Join(filepath.Base(filepath.Dir(c.SrcPath)), c.SrcName())
  250. }
  251. // IsPkgMain returns true if it is in the main package.
  252. func (c *Call) IsPkgMain() bool {
  253. return c.Func.PkgName() == "main"
  254. }
  255. const testMainSrc = "_test" + string(os.PathSeparator) + "_testmain.go"
  256. // updateLocations initializes LocalSrcPath and IsStdlib.
  257. func (c *Call) updateLocations(goroot, localgoroot string, gopaths map[string]string) {
  258. if c.SrcPath != "" {
  259. // Always check GOROOT first, then GOPATH.
  260. if strings.HasPrefix(c.SrcPath, goroot) {
  261. // Replace remote GOROOT with local GOROOT.
  262. c.LocalSrcPath = filepath.Join(localgoroot, c.SrcPath[len(goroot):])
  263. } else {
  264. // Replace remote GOPATH with local GOPATH.
  265. c.LocalSrcPath = c.SrcPath
  266. // TODO(maruel): Sort for deterministic behavior?
  267. for prefix, dest := range gopaths {
  268. if strings.HasPrefix(c.SrcPath, prefix) {
  269. c.LocalSrcPath = filepath.Join(dest, c.SrcPath[len(prefix):])
  270. break
  271. }
  272. }
  273. }
  274. }
  275. // Consider _test/_testmain.go as stdlib since it's injected by "go test".
  276. c.IsStdlib = (goroot != "" && strings.HasPrefix(c.SrcPath, goroot)) || c.PkgSrc() == testMainSrc
  277. }
  278. // Stack is a call stack.
  279. type Stack struct {
  280. Calls []Call // Call stack. First is original function, last is leaf function.
  281. Elided bool // Happens when there's >100 items in Stack, currently hardcoded in package runtime.
  282. }
  283. // equal returns true on if both call stacks are exactly equal.
  284. func (s *Stack) equal(r *Stack) bool {
  285. if len(s.Calls) != len(r.Calls) || s.Elided != r.Elided {
  286. return false
  287. }
  288. for i := range s.Calls {
  289. if !s.Calls[i].equal(&r.Calls[i]) {
  290. return false
  291. }
  292. }
  293. return true
  294. }
  295. // similar returns true if the two Stack are equal or almost but not quite
  296. // equal.
  297. func (s *Stack) similar(r *Stack, similar Similarity) bool {
  298. if len(s.Calls) != len(r.Calls) || s.Elided != r.Elided {
  299. return false
  300. }
  301. for i := range s.Calls {
  302. if !s.Calls[i].similar(&r.Calls[i], similar) {
  303. return false
  304. }
  305. }
  306. return true
  307. }
  308. // merge merges two similar Stack, zapping out differences.
  309. func (s *Stack) merge(r *Stack) *Stack {
  310. // Assumes similar stacks have the same length.
  311. out := &Stack{
  312. Calls: make([]Call, len(s.Calls)),
  313. Elided: s.Elided,
  314. }
  315. for i := range s.Calls {
  316. out.Calls[i] = s.Calls[i].merge(&r.Calls[i])
  317. }
  318. return out
  319. }
  320. // less compares two Stack, where the ones that are less are more
  321. // important, so they come up front.
  322. //
  323. // A Stack with more private functions is 'less' so it is at the top.
  324. // Inversely, a Stack with only public functions is 'more' so it is at the
  325. // bottom.
  326. func (s *Stack) less(r *Stack) bool {
  327. lStdlib := 0
  328. lPrivate := 0
  329. for _, c := range s.Calls {
  330. if c.IsStdlib {
  331. lStdlib++
  332. } else {
  333. lPrivate++
  334. }
  335. }
  336. rStdlib := 0
  337. rPrivate := 0
  338. for _, s := range r.Calls {
  339. if s.IsStdlib {
  340. rStdlib++
  341. } else {
  342. rPrivate++
  343. }
  344. }
  345. if lPrivate > rPrivate {
  346. return true
  347. }
  348. if lPrivate < rPrivate {
  349. return false
  350. }
  351. if lStdlib > rStdlib {
  352. return false
  353. }
  354. if lStdlib < rStdlib {
  355. return true
  356. }
  357. // Stack lengths are the same.
  358. for x := range s.Calls {
  359. if s.Calls[x].Func.Raw < r.Calls[x].Func.Raw {
  360. return true
  361. }
  362. if s.Calls[x].Func.Raw > r.Calls[x].Func.Raw {
  363. return true
  364. }
  365. if s.Calls[x].PkgSrc() < r.Calls[x].PkgSrc() {
  366. return true
  367. }
  368. if s.Calls[x].PkgSrc() > r.Calls[x].PkgSrc() {
  369. return true
  370. }
  371. if s.Calls[x].Line < r.Calls[x].Line {
  372. return true
  373. }
  374. if s.Calls[x].Line > r.Calls[x].Line {
  375. return true
  376. }
  377. }
  378. return false
  379. }
  380. func (s *Stack) updateLocations(goroot, localgoroot string, gopaths map[string]string) {
  381. for i := range s.Calls {
  382. s.Calls[i].updateLocations(goroot, localgoroot, gopaths)
  383. }
  384. }
  385. // Signature represents the signature of one or multiple goroutines.
  386. //
  387. // It is effectively the stack trace plus the goroutine internal bits, like
  388. // it's state, if it is thread locked, which call site created this goroutine,
  389. // etc.
  390. type Signature struct {
  391. // Use git grep 'gopark(|unlock)\(' to find them all plus everything listed
  392. // in runtime/traceback.go. Valid values includes:
  393. // - chan send, chan receive, select
  394. // - finalizer wait, mark wait (idle),
  395. // - Concurrent GC wait, GC sweep wait, force gc (idle)
  396. // - IO wait, panicwait
  397. // - semacquire, semarelease
  398. // - sleep, timer goroutine (idle)
  399. // - trace reader (blocked)
  400. // Stuck cases:
  401. // - chan send (nil chan), chan receive (nil chan), select (no cases)
  402. // Runnable states:
  403. // - idle, runnable, running, syscall, waiting, dead, enqueue, copystack,
  404. // Scan states:
  405. // - scan, scanrunnable, scanrunning, scansyscall, scanwaiting, scandead,
  406. // scanenqueue
  407. State string
  408. CreatedBy Call // Which other goroutine which created this one.
  409. SleepMin int // Wait time in minutes, if applicable.
  410. SleepMax int // Wait time in minutes, if applicable.
  411. Stack Stack
  412. Locked bool // Locked to an OS thread.
  413. }
  414. // equal returns true only if both signatures are exactly equal.
  415. func (s *Signature) equal(r *Signature) bool {
  416. if s.State != r.State || !s.CreatedBy.equal(&r.CreatedBy) || s.Locked != r.Locked || s.SleepMin != r.SleepMin || s.SleepMax != r.SleepMax {
  417. return false
  418. }
  419. return s.Stack.equal(&r.Stack)
  420. }
  421. // similar returns true if the two Signature are equal or almost but not quite
  422. // equal.
  423. func (s *Signature) similar(r *Signature, similar Similarity) bool {
  424. if s.State != r.State || !s.CreatedBy.similar(&r.CreatedBy, similar) {
  425. return false
  426. }
  427. if similar == ExactFlags && s.Locked != r.Locked {
  428. return false
  429. }
  430. return s.Stack.similar(&r.Stack, similar)
  431. }
  432. // merge merges two similar Signature, zapping out differences.
  433. func (s *Signature) merge(r *Signature) *Signature {
  434. min := s.SleepMin
  435. if r.SleepMin < min {
  436. min = r.SleepMin
  437. }
  438. max := s.SleepMax
  439. if r.SleepMax > max {
  440. max = r.SleepMax
  441. }
  442. return &Signature{
  443. State: s.State, // Drop right side.
  444. CreatedBy: s.CreatedBy, // Drop right side.
  445. SleepMin: min,
  446. SleepMax: max,
  447. Stack: *s.Stack.merge(&r.Stack),
  448. Locked: s.Locked || r.Locked, // TODO(maruel): This is weirdo.
  449. }
  450. }
  451. // less compares two Signature, where the ones that are less are more
  452. // important, so they come up front. A Signature with more private functions is
  453. // 'less' so it is at the top. Inversely, a Signature with only public
  454. // functions is 'more' so it is at the bottom.
  455. func (s *Signature) less(r *Signature) bool {
  456. if s.Stack.less(&r.Stack) {
  457. return true
  458. }
  459. if r.Stack.less(&s.Stack) {
  460. return false
  461. }
  462. if s.Locked && !r.Locked {
  463. return true
  464. }
  465. if r.Locked && !s.Locked {
  466. return false
  467. }
  468. if s.State < r.State {
  469. return true
  470. }
  471. if s.State > r.State {
  472. return false
  473. }
  474. return false
  475. }
  476. // SleepString returns a string "N-M minutes" if the goroutine(s) slept for a
  477. // long time.
  478. //
  479. // Returns an empty string otherwise.
  480. func (s *Signature) SleepString() string {
  481. if s.SleepMax == 0 {
  482. return ""
  483. }
  484. if s.SleepMin != s.SleepMax {
  485. return fmt.Sprintf("%d~%d minutes", s.SleepMin, s.SleepMax)
  486. }
  487. return fmt.Sprintf("%d minutes", s.SleepMax)
  488. }
  489. // CreatedByString return a short context about the origin of this goroutine
  490. // signature.
  491. func (s *Signature) CreatedByString(fullPath bool) string {
  492. created := s.CreatedBy.Func.PkgDotName()
  493. if created == "" {
  494. return ""
  495. }
  496. created += " @ "
  497. if fullPath {
  498. created += s.CreatedBy.FullSrcLine()
  499. } else {
  500. created += s.CreatedBy.SrcLine()
  501. }
  502. return created
  503. }
  504. func (s *Signature) updateLocations(goroot, localgoroot string, gopaths map[string]string) {
  505. s.CreatedBy.updateLocations(goroot, localgoroot, gopaths)
  506. s.Stack.updateLocations(goroot, localgoroot, gopaths)
  507. }
  508. // Goroutine represents the state of one goroutine, including the stack trace.
  509. type Goroutine struct {
  510. Signature // It's stack trace, internal bits, state, which call site created it, etc.
  511. ID int // Goroutine ID.
  512. First bool // First is the goroutine first printed, normally the one that crashed.
  513. }
  514. // Private stuff.
  515. // nameArguments is a post-processing step where Args are 'named' with numbers.
  516. func nameArguments(goroutines []*Goroutine) {
  517. // Set a name for any pointer occurring more than once.
  518. type object struct {
  519. args []*Arg
  520. inPrimary bool
  521. id int
  522. }
  523. objects := map[uint64]object{}
  524. // Enumerate all the arguments.
  525. for i := range goroutines {
  526. for j := range goroutines[i].Stack.Calls {
  527. for k := range goroutines[i].Stack.Calls[j].Args.Values {
  528. arg := goroutines[i].Stack.Calls[j].Args.Values[k]
  529. if arg.IsPtr() {
  530. objects[arg.Value] = object{
  531. args: append(objects[arg.Value].args, &goroutines[i].Stack.Calls[j].Args.Values[k]),
  532. inPrimary: objects[arg.Value].inPrimary || i == 0,
  533. }
  534. }
  535. }
  536. }
  537. // CreatedBy.Args is never set.
  538. }
  539. order := make(uint64Slice, 0, len(objects)/2)
  540. for k, obj := range objects {
  541. if len(obj.args) > 1 && obj.inPrimary {
  542. order = append(order, k)
  543. }
  544. }
  545. sort.Sort(order)
  546. nextID := 1
  547. for _, k := range order {
  548. for _, arg := range objects[k].args {
  549. arg.Name = fmt.Sprintf("#%d", nextID)
  550. }
  551. nextID++
  552. }
  553. // Now do the rest. This is done so the output is deterministic.
  554. order = make(uint64Slice, 0, len(objects))
  555. for k := range objects {
  556. order = append(order, k)
  557. }
  558. sort.Sort(order)
  559. for _, k := range order {
  560. // Process the remaining pointers, they were not referenced by primary
  561. // thread so will have higher IDs.
  562. if objects[k].inPrimary {
  563. continue
  564. }
  565. for _, arg := range objects[k].args {
  566. arg.Name = fmt.Sprintf("#%d", nextID)
  567. }
  568. nextID++
  569. }
  570. }
  571. type uint64Slice []uint64
  572. func (a uint64Slice) Len() int { return len(a) }
  573. func (a uint64Slice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
  574. func (a uint64Slice) Less(i, j int) bool { return a[i] < a[j] }