dump.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. /*
  2. * Copyright (c) 2013 Dave Collins <dave@davec.name>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. package spew
  17. import (
  18. "bytes"
  19. "encoding/hex"
  20. "fmt"
  21. "io"
  22. "os"
  23. "reflect"
  24. "regexp"
  25. "sort"
  26. "strconv"
  27. "strings"
  28. )
  29. var (
  30. // uint8Type is a reflect.Type representing a uint8. It is used to
  31. // convert cgo types to uint8 slices for hexdumping.
  32. uint8Type = reflect.TypeOf(uint8(0))
  33. // cCharRE is a regular expression that matches a cgo char.
  34. // It is used to detect character arrays to hexdump them.
  35. cCharRE = regexp.MustCompile("^.*\\._Ctype_char$")
  36. // cUnsignedCharRE is a regular expression that matches a cgo unsigned
  37. // char. It is used to detect unsigned character arrays to hexdump
  38. // them.
  39. cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$")
  40. // cUint8tCharRE is a regular expression that matches a cgo uint8_t.
  41. // It is used to detect uint8_t arrays to hexdump them.
  42. cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$")
  43. )
  44. // dumpState contains information about the state of a dump operation.
  45. type dumpState struct {
  46. w io.Writer
  47. depth int
  48. pointers map[uintptr]int
  49. ignoreNextType bool
  50. ignoreNextIndent bool
  51. cs *ConfigState
  52. }
  53. // indent performs indentation according to the depth level and cs.Indent
  54. // option.
  55. func (d *dumpState) indent() {
  56. if d.ignoreNextIndent {
  57. d.ignoreNextIndent = false
  58. return
  59. }
  60. d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))
  61. }
  62. // unpackValue returns values inside of non-nil interfaces when possible.
  63. // This is useful for data types like structs, arrays, slices, and maps which
  64. // can contain varying types packed inside an interface.
  65. func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
  66. if v.Kind() == reflect.Interface && !v.IsNil() {
  67. v = v.Elem()
  68. }
  69. return v
  70. }
  71. // dumpPtr handles formatting of pointers by indirecting them as necessary.
  72. func (d *dumpState) dumpPtr(v reflect.Value) {
  73. // Remove pointers at or below the current depth from map used to detect
  74. // circular refs.
  75. for k, depth := range d.pointers {
  76. if depth >= d.depth {
  77. delete(d.pointers, k)
  78. }
  79. }
  80. // Keep list of all dereferenced pointers to show later.
  81. pointerChain := make([]uintptr, 0)
  82. // Figure out how many levels of indirection there are by dereferencing
  83. // pointers and unpacking interfaces down the chain while detecting circular
  84. // references.
  85. nilFound := false
  86. cycleFound := false
  87. indirects := 0
  88. ve := v
  89. for ve.Kind() == reflect.Ptr {
  90. if ve.IsNil() {
  91. nilFound = true
  92. break
  93. }
  94. indirects++
  95. addr := ve.Pointer()
  96. pointerChain = append(pointerChain, addr)
  97. if pd, ok := d.pointers[addr]; ok && pd < d.depth {
  98. cycleFound = true
  99. indirects--
  100. break
  101. }
  102. d.pointers[addr] = d.depth
  103. ve = ve.Elem()
  104. if ve.Kind() == reflect.Interface {
  105. if ve.IsNil() {
  106. nilFound = true
  107. break
  108. }
  109. ve = ve.Elem()
  110. }
  111. }
  112. // Display type information.
  113. d.w.Write(openParenBytes)
  114. d.w.Write(bytes.Repeat(asteriskBytes, indirects))
  115. d.w.Write([]byte(ve.Type().String()))
  116. d.w.Write(closeParenBytes)
  117. // Display pointer information.
  118. if len(pointerChain) > 0 {
  119. d.w.Write(openParenBytes)
  120. for i, addr := range pointerChain {
  121. if i > 0 {
  122. d.w.Write(pointerChainBytes)
  123. }
  124. printHexPtr(d.w, addr)
  125. }
  126. d.w.Write(closeParenBytes)
  127. }
  128. // Display dereferenced value.
  129. d.w.Write(openParenBytes)
  130. switch {
  131. case nilFound == true:
  132. d.w.Write(nilAngleBytes)
  133. case cycleFound == true:
  134. d.w.Write(circularBytes)
  135. default:
  136. d.ignoreNextType = true
  137. d.dump(ve)
  138. }
  139. d.w.Write(closeParenBytes)
  140. }
  141. // dumpSlice handles formatting of arrays and slices. Byte (uint8 under
  142. // reflection) arrays and slices are dumped in hexdump -C fashion.
  143. func (d *dumpState) dumpSlice(v reflect.Value) {
  144. // Determine whether this type should be hex dumped or not. Also,
  145. // for types which should be hexdumped, try to use the underlying data
  146. // first, then fall back to trying to convert them to a uint8 slice.
  147. var buf []uint8
  148. doConvert := false
  149. doHexDump := false
  150. numEntries := v.Len()
  151. if numEntries > 0 {
  152. vt := v.Index(0).Type()
  153. vts := vt.String()
  154. switch {
  155. // C types that need to be converted.
  156. case cCharRE.MatchString(vts):
  157. fallthrough
  158. case cUnsignedCharRE.MatchString(vts):
  159. fallthrough
  160. case cUint8tCharRE.MatchString(vts):
  161. doConvert = true
  162. // Try to use existing uint8 slices and fall back to converting
  163. // and copying if that fails.
  164. case vt.Kind() == reflect.Uint8:
  165. // We need an addressable interface to convert the type back
  166. // into a byte slice. However, the reflect package won't give
  167. // us an interface on certain things like unexported struct
  168. // fields in order to enforce visibility rules. We use unsafe
  169. // to bypass these restrictions since this package does not
  170. // mutate the values.
  171. vs := v
  172. if !vs.CanInterface() || !vs.CanAddr() {
  173. vs = unsafeReflectValue(vs)
  174. }
  175. vs = vs.Slice(0, numEntries)
  176. // Use the existing uint8 slice if it can be type
  177. // asserted.
  178. iface := vs.Interface()
  179. if slice, ok := iface.([]uint8); ok {
  180. buf = slice
  181. doHexDump = true
  182. break
  183. }
  184. // The underlying data needs to be converted if it can't
  185. // be type asserted to a uint8 slice.
  186. doConvert = true
  187. }
  188. // Copy and convert the underlying type if needed.
  189. if doConvert && vt.ConvertibleTo(uint8Type) {
  190. // Convert and copy each element into a uint8 byte
  191. // slice.
  192. buf = make([]uint8, numEntries)
  193. for i := 0; i < numEntries; i++ {
  194. vv := v.Index(i)
  195. buf[i] = uint8(vv.Convert(uint8Type).Uint())
  196. }
  197. doHexDump = true
  198. }
  199. }
  200. // Hexdump the entire slice as needed.
  201. if doHexDump {
  202. indent := strings.Repeat(d.cs.Indent, d.depth)
  203. str := indent + hex.Dump(buf)
  204. str = strings.Replace(str, "\n", "\n"+indent, -1)
  205. str = strings.TrimRight(str, d.cs.Indent)
  206. d.w.Write([]byte(str))
  207. return
  208. }
  209. // Recursively call dump for each item.
  210. for i := 0; i < numEntries; i++ {
  211. d.dump(d.unpackValue(v.Index(i)))
  212. if i < (numEntries - 1) {
  213. d.w.Write(commaNewlineBytes)
  214. } else {
  215. d.w.Write(newlineBytes)
  216. }
  217. }
  218. }
  219. type valuesSorter struct {
  220. values []reflect.Value
  221. }
  222. func (s *valuesSorter) Len() int {
  223. return len(s.values)
  224. }
  225. func (s *valuesSorter) Swap(i, j int) {
  226. s.values[i], s.values[j] = s.values[j], s.values[i]
  227. }
  228. func (s *valuesSorter) Less(i, j int) bool {
  229. switch s.values[i].Kind() {
  230. case reflect.Bool:
  231. return !s.values[i].Bool() && s.values[j].Bool()
  232. case reflect.Float32, reflect.Float64:
  233. return s.values[i].Float() < s.values[j].Float()
  234. case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
  235. return s.values[i].Int() < s.values[j].Int()
  236. case reflect.String:
  237. return s.values[i].String() < s.values[j].String()
  238. case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
  239. return s.values[i].Uint() < s.values[j].Uint()
  240. case reflect.Uintptr:
  241. return s.values[i].UnsafeAddr() < s.values[j].UnsafeAddr()
  242. }
  243. panic("notimplemented")
  244. }
  245. // Generic sort function for native types: int, uint, bool, string and uintptr.
  246. // Other inputs are left unchanged.
  247. func SortValues(values []reflect.Value) {
  248. if len(values) == 0 {
  249. return
  250. }
  251. switch values[0].Kind() {
  252. case reflect.Bool:
  253. sort.Sort(&valuesSorter{values})
  254. case reflect.Float32, reflect.Float64:
  255. sort.Sort(&valuesSorter{values})
  256. case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
  257. sort.Sort(&valuesSorter{values})
  258. case reflect.String:
  259. sort.Sort(&valuesSorter{values})
  260. case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
  261. sort.Sort(&valuesSorter{values})
  262. case reflect.Uintptr:
  263. sort.Sort(&valuesSorter{values})
  264. }
  265. }
  266. // dump is the main workhorse for dumping a value. It uses the passed reflect
  267. // value to figure out what kind of object we are dealing with and formats it
  268. // appropriately. It is a recursive function, however circular data structures
  269. // are detected and handled properly.
  270. func (d *dumpState) dump(v reflect.Value) {
  271. // Handle invalid reflect values immediately.
  272. kind := v.Kind()
  273. if kind == reflect.Invalid {
  274. d.w.Write(invalidAngleBytes)
  275. return
  276. }
  277. // Handle pointers specially.
  278. if kind == reflect.Ptr {
  279. d.indent()
  280. d.dumpPtr(v)
  281. return
  282. }
  283. // Print type information unless already handled elsewhere.
  284. if !d.ignoreNextType {
  285. d.indent()
  286. d.w.Write(openParenBytes)
  287. d.w.Write([]byte(v.Type().String()))
  288. d.w.Write(closeParenBytes)
  289. d.w.Write(spaceBytes)
  290. }
  291. d.ignoreNextType = false
  292. // Call Stringer/error interfaces if they exist and the handle methods flag
  293. // is enabled
  294. if !d.cs.DisableMethods {
  295. if (kind != reflect.Invalid) && (kind != reflect.Interface) {
  296. if handled := handleMethods(d.cs, d.w, v); handled {
  297. return
  298. }
  299. }
  300. }
  301. switch kind {
  302. case reflect.Invalid:
  303. // Do nothing. We should never get here since invalid has already
  304. // been handled above.
  305. case reflect.Bool:
  306. printBool(d.w, v.Bool())
  307. case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
  308. printInt(d.w, v.Int(), 10)
  309. case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
  310. printUint(d.w, v.Uint(), 10)
  311. case reflect.Float32:
  312. printFloat(d.w, v.Float(), 32)
  313. case reflect.Float64:
  314. printFloat(d.w, v.Float(), 64)
  315. case reflect.Complex64:
  316. printComplex(d.w, v.Complex(), 32)
  317. case reflect.Complex128:
  318. printComplex(d.w, v.Complex(), 64)
  319. case reflect.Slice:
  320. if v.IsNil() {
  321. d.w.Write(nilAngleBytes)
  322. break
  323. }
  324. fallthrough
  325. case reflect.Array:
  326. d.w.Write(openBraceNewlineBytes)
  327. d.depth++
  328. if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
  329. d.indent()
  330. d.w.Write(maxNewlineBytes)
  331. } else {
  332. d.dumpSlice(v)
  333. }
  334. d.depth--
  335. d.indent()
  336. d.w.Write(closeBraceBytes)
  337. case reflect.String:
  338. d.w.Write([]byte(strconv.Quote(v.String())))
  339. case reflect.Interface:
  340. // The only time we should get here is for nil interfaces due to
  341. // unpackValue calls.
  342. if v.IsNil() {
  343. d.w.Write(nilAngleBytes)
  344. }
  345. case reflect.Ptr:
  346. // Do nothing. We should never get here since pointers have already
  347. // been handled above.
  348. case reflect.Map:
  349. d.w.Write(openBraceNewlineBytes)
  350. d.depth++
  351. if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
  352. d.indent()
  353. d.w.Write(maxNewlineBytes)
  354. } else {
  355. numEntries := v.Len()
  356. keys := v.MapKeys()
  357. if d.cs.SortKeys {
  358. SortValues(keys)
  359. }
  360. for i, key := range keys {
  361. d.dump(d.unpackValue(key))
  362. d.w.Write(colonSpaceBytes)
  363. d.ignoreNextIndent = true
  364. d.dump(d.unpackValue(v.MapIndex(key)))
  365. if i < (numEntries - 1) {
  366. d.w.Write(commaNewlineBytes)
  367. } else {
  368. d.w.Write(newlineBytes)
  369. }
  370. }
  371. }
  372. d.depth--
  373. d.indent()
  374. d.w.Write(closeBraceBytes)
  375. case reflect.Struct:
  376. d.w.Write(openBraceNewlineBytes)
  377. d.depth++
  378. if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
  379. d.indent()
  380. d.w.Write(maxNewlineBytes)
  381. } else {
  382. vt := v.Type()
  383. numFields := v.NumField()
  384. for i := 0; i < numFields; i++ {
  385. d.indent()
  386. vtf := vt.Field(i)
  387. d.w.Write([]byte(vtf.Name))
  388. d.w.Write(colonSpaceBytes)
  389. d.ignoreNextIndent = true
  390. d.dump(d.unpackValue(v.Field(i)))
  391. if i < (numFields - 1) {
  392. d.w.Write(commaNewlineBytes)
  393. } else {
  394. d.w.Write(newlineBytes)
  395. }
  396. }
  397. }
  398. d.depth--
  399. d.indent()
  400. d.w.Write(closeBraceBytes)
  401. case reflect.Uintptr:
  402. printHexPtr(d.w, uintptr(v.Uint()))
  403. case reflect.UnsafePointer, reflect.Chan, reflect.Func:
  404. printHexPtr(d.w, v.Pointer())
  405. // There were not any other types at the time this code was written, but
  406. // fall back to letting the default fmt package handle it in case any new
  407. // types are added.
  408. default:
  409. if v.CanInterface() {
  410. fmt.Fprintf(d.w, "%v", v.Interface())
  411. } else {
  412. fmt.Fprintf(d.w, "%v", v.String())
  413. }
  414. }
  415. }
  416. // fdump is a helper function to consolidate the logic from the various public
  417. // methods which take varying writers and config states.
  418. func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
  419. for _, arg := range a {
  420. if arg == nil {
  421. w.Write(interfaceBytes)
  422. w.Write(spaceBytes)
  423. w.Write(nilAngleBytes)
  424. w.Write(newlineBytes)
  425. continue
  426. }
  427. d := dumpState{w: w, cs: cs}
  428. d.pointers = make(map[uintptr]int)
  429. d.dump(reflect.ValueOf(arg))
  430. d.w.Write(newlineBytes)
  431. }
  432. }
  433. // Fdump formats and displays the passed arguments to io.Writer w. It formats
  434. // exactly the same as Dump.
  435. func Fdump(w io.Writer, a ...interface{}) {
  436. fdump(&Config, w, a...)
  437. }
  438. // Sdump returns a string with the passed arguments formatted exactly the same
  439. // as Dump.
  440. func Sdump(a ...interface{}) string {
  441. var buf bytes.Buffer
  442. fdump(&Config, &buf, a...)
  443. return buf.String()
  444. }
  445. /*
  446. Dump displays the passed parameters to standard out with newlines, customizable
  447. indentation, and additional debug information such as complete types and all
  448. pointer addresses used to indirect to the final value. It provides the
  449. following features over the built-in printing facilities provided by the fmt
  450. package:
  451. * Pointers are dereferenced and followed
  452. * Circular data structures are detected and handled properly
  453. * Custom Stringer/error interfaces are optionally invoked, including
  454. on unexported types
  455. * Custom types which only implement the Stringer/error interfaces via
  456. a pointer receiver are optionally invoked when passing non-pointer
  457. variables
  458. * Byte arrays and slices are dumped like the hexdump -C command which
  459. includes offsets, byte values in hex, and ASCII output
  460. The configuration options are controlled by an exported package global,
  461. spew.Config. See ConfigState for options documentation.
  462. See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
  463. get the formatted result as a string.
  464. */
  465. func Dump(a ...interface{}) {
  466. fdump(&Config, os.Stdout, a...)
  467. }