2 * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
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.
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.
32 // uint8Type is a reflect.Type representing a uint8. It is used to
33 // convert cgo types to uint8 slices for hexdumping.
34 uint8Type = reflect.TypeOf(uint8(0))
36 // cCharRE is a regular expression that matches a cgo char.
37 // It is used to detect character arrays to hexdump them.
38 cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`)
40 // cUnsignedCharRE is a regular expression that matches a cgo unsigned
41 // char. It is used to detect unsigned character arrays to hexdump
43 cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`)
45 // cUint8tCharRE is a regular expression that matches a cgo uint8_t.
46 // It is used to detect uint8_t arrays to hexdump them.
47 cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`)
50 // dumpState contains information about the state of a dump operation.
51 type dumpState struct {
54 pointers map[uintptr]int
60 // indent performs indentation according to the depth level and cs.Indent
62 func (d *dumpState) indent() {
63 if d.ignoreNextIndent {
64 d.ignoreNextIndent = false
67 d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))
70 // unpackValue returns values inside of non-nil interfaces when possible.
71 // This is useful for data types like structs, arrays, slices, and maps which
72 // can contain varying types packed inside an interface.
73 func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
74 if v.Kind() == reflect.Interface && !v.IsNil() {
80 // dumpPtr handles formatting of pointers by indirecting them as necessary.
81 func (d *dumpState) dumpPtr(v reflect.Value) {
82 // Remove pointers at or below the current depth from map used to detect
84 for k, depth := range d.pointers {
90 // Keep list of all dereferenced pointers to show later.
91 pointerChain := make([]uintptr, 0)
93 // Figure out how many levels of indirection there are by dereferencing
94 // pointers and unpacking interfaces down the chain while detecting circular
100 for ve.Kind() == reflect.Ptr {
107 pointerChain = append(pointerChain, addr)
108 if pd, ok := d.pointers[addr]; ok && pd < d.depth {
113 d.pointers[addr] = d.depth
116 if ve.Kind() == reflect.Interface {
125 // Display type information.
126 d.w.Write(openParenBytes)
127 d.w.Write(bytes.Repeat(asteriskBytes, indirects))
128 d.w.Write([]byte(ve.Type().String()))
129 d.w.Write(closeParenBytes)
131 // Display pointer information.
132 if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 {
133 d.w.Write(openParenBytes)
134 for i, addr := range pointerChain {
136 d.w.Write(pointerChainBytes)
138 printHexPtr(d.w, addr)
140 d.w.Write(closeParenBytes)
143 // Display dereferenced value.
144 d.w.Write(openParenBytes)
147 d.w.Write(nilAngleBytes)
150 d.w.Write(circularBytes)
153 d.ignoreNextType = true
156 d.w.Write(closeParenBytes)
159 // dumpSlice handles formatting of arrays and slices. Byte (uint8 under
160 // reflection) arrays and slices are dumped in hexdump -C fashion.
161 func (d *dumpState) dumpSlice(v reflect.Value) {
162 // Determine whether this type should be hex dumped or not. Also,
163 // for types which should be hexdumped, try to use the underlying data
164 // first, then fall back to trying to convert them to a uint8 slice.
168 numEntries := v.Len()
170 vt := v.Index(0).Type()
173 // C types that need to be converted.
174 case cCharRE.MatchString(vts):
176 case cUnsignedCharRE.MatchString(vts):
178 case cUint8tCharRE.MatchString(vts):
181 // Try to use existing uint8 slices and fall back to converting
182 // and copying if that fails.
183 case vt.Kind() == reflect.Uint8:
184 // We need an addressable interface to convert the type
185 // to a byte slice. However, the reflect package won't
186 // give us an interface on certain things like
187 // unexported struct fields in order to enforce
188 // visibility rules. We use unsafe, when available, to
189 // bypass these restrictions since this package does not
190 // mutate the values.
192 if !vs.CanInterface() || !vs.CanAddr() {
193 vs = unsafeReflectValue(vs)
196 vs = vs.Slice(0, numEntries)
198 // Use the existing uint8 slice if it can be
200 iface := vs.Interface()
201 if slice, ok := iface.([]uint8); ok {
208 // The underlying data needs to be converted if it can't
209 // be type asserted to a uint8 slice.
213 // Copy and convert the underlying type if needed.
214 if doConvert && vt.ConvertibleTo(uint8Type) {
215 // Convert and copy each element into a uint8 byte
217 buf = make([]uint8, numEntries)
218 for i := 0; i < numEntries; i++ {
220 buf[i] = uint8(vv.Convert(uint8Type).Uint())
226 // Hexdump the entire slice as needed.
228 indent := strings.Repeat(d.cs.Indent, d.depth)
229 str := indent + hex.Dump(buf)
230 str = strings.Replace(str, "\n", "\n"+indent, -1)
231 str = strings.TrimRight(str, d.cs.Indent)
232 d.w.Write([]byte(str))
236 // Recursively call dump for each item.
237 for i := 0; i < numEntries; i++ {
238 d.dump(d.unpackValue(v.Index(i)))
239 if i < (numEntries - 1) {
240 d.w.Write(commaNewlineBytes)
242 d.w.Write(newlineBytes)
247 // dump is the main workhorse for dumping a value. It uses the passed reflect
248 // value to figure out what kind of object we are dealing with and formats it
249 // appropriately. It is a recursive function, however circular data structures
250 // are detected and handled properly.
251 func (d *dumpState) dump(v reflect.Value) {
252 // Handle invalid reflect values immediately.
254 if kind == reflect.Invalid {
255 d.w.Write(invalidAngleBytes)
259 // Handle pointers specially.
260 if kind == reflect.Ptr {
266 // Print type information unless already handled elsewhere.
267 if !d.ignoreNextType {
269 d.w.Write(openParenBytes)
270 d.w.Write([]byte(v.Type().String()))
271 d.w.Write(closeParenBytes)
272 d.w.Write(spaceBytes)
274 d.ignoreNextType = false
276 // Display length and capacity if the built-in len and cap functions
277 // work with the value's kind and the len/cap itself is non-zero.
278 valueLen, valueCap := 0, 0
280 case reflect.Array, reflect.Slice, reflect.Chan:
281 valueLen, valueCap = v.Len(), v.Cap()
282 case reflect.Map, reflect.String:
285 if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 {
286 d.w.Write(openParenBytes)
288 d.w.Write(lenEqualsBytes)
289 printInt(d.w, int64(valueLen), 10)
291 if !d.cs.DisableCapacities && valueCap != 0 {
293 d.w.Write(spaceBytes)
295 d.w.Write(capEqualsBytes)
296 printInt(d.w, int64(valueCap), 10)
298 d.w.Write(closeParenBytes)
299 d.w.Write(spaceBytes)
302 // Call Stringer/error interfaces if they exist and the handle methods flag
304 if !d.cs.DisableMethods {
305 if (kind != reflect.Invalid) && (kind != reflect.Interface) {
306 if handled := handleMethods(d.cs, d.w, v); handled {
313 case reflect.Invalid:
314 // Do nothing. We should never get here since invalid has already
315 // been handled above.
318 printBool(d.w, v.Bool())
320 case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
321 printInt(d.w, v.Int(), 10)
323 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
324 printUint(d.w, v.Uint(), 10)
326 case reflect.Float32:
327 printFloat(d.w, v.Float(), 32)
329 case reflect.Float64:
330 printFloat(d.w, v.Float(), 64)
332 case reflect.Complex64:
333 printComplex(d.w, v.Complex(), 32)
335 case reflect.Complex128:
336 printComplex(d.w, v.Complex(), 64)
340 d.w.Write(nilAngleBytes)
346 d.w.Write(openBraceNewlineBytes)
348 if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
350 d.w.Write(maxNewlineBytes)
356 d.w.Write(closeBraceBytes)
359 d.w.Write([]byte(strconv.Quote(v.String())))
361 case reflect.Interface:
362 // The only time we should get here is for nil interfaces due to
363 // unpackValue calls.
365 d.w.Write(nilAngleBytes)
369 // Do nothing. We should never get here since pointers have already
370 // been handled above.
373 // nil maps should be indicated as different than empty maps
375 d.w.Write(nilAngleBytes)
379 d.w.Write(openBraceNewlineBytes)
381 if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
383 d.w.Write(maxNewlineBytes)
385 numEntries := v.Len()
388 sortValues(keys, d.cs)
390 for i, key := range keys {
391 d.dump(d.unpackValue(key))
392 d.w.Write(colonSpaceBytes)
393 d.ignoreNextIndent = true
394 d.dump(d.unpackValue(v.MapIndex(key)))
395 if i < (numEntries - 1) {
396 d.w.Write(commaNewlineBytes)
398 d.w.Write(newlineBytes)
404 d.w.Write(closeBraceBytes)
407 d.w.Write(openBraceNewlineBytes)
409 if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
411 d.w.Write(maxNewlineBytes)
414 numFields := v.NumField()
415 for i := 0; i < numFields; i++ {
418 d.w.Write([]byte(vtf.Name))
419 d.w.Write(colonSpaceBytes)
420 d.ignoreNextIndent = true
421 d.dump(d.unpackValue(v.Field(i)))
422 if i < (numFields - 1) {
423 d.w.Write(commaNewlineBytes)
425 d.w.Write(newlineBytes)
431 d.w.Write(closeBraceBytes)
433 case reflect.Uintptr:
434 printHexPtr(d.w, uintptr(v.Uint()))
436 case reflect.UnsafePointer, reflect.Chan, reflect.Func:
437 printHexPtr(d.w, v.Pointer())
439 // There were not any other types at the time this code was written, but
440 // fall back to letting the default fmt package handle it in case any new
443 if v.CanInterface() {
444 fmt.Fprintf(d.w, "%v", v.Interface())
446 fmt.Fprintf(d.w, "%v", v.String())
451 // fdump is a helper function to consolidate the logic from the various public
452 // methods which take varying writers and config states.
453 func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
454 for _, arg := range a {
456 w.Write(interfaceBytes)
458 w.Write(nilAngleBytes)
459 w.Write(newlineBytes)
463 d := dumpState{w: w, cs: cs}
464 d.pointers = make(map[uintptr]int)
465 d.dump(reflect.ValueOf(arg))
466 d.w.Write(newlineBytes)
470 // Fdump formats and displays the passed arguments to io.Writer w. It formats
471 // exactly the same as Dump.
472 func Fdump(w io.Writer, a ...interface{}) {
473 fdump(&Config, w, a...)
476 // Sdump returns a string with the passed arguments formatted exactly the same
478 func Sdump(a ...interface{}) string {
480 fdump(&Config, &buf, a...)
485 Dump displays the passed parameters to standard out with newlines, customizable
486 indentation, and additional debug information such as complete types and all
487 pointer addresses used to indirect to the final value. It provides the
488 following features over the built-in printing facilities provided by the fmt
491 * Pointers are dereferenced and followed
492 * Circular data structures are detected and handled properly
493 * Custom Stringer/error interfaces are optionally invoked, including
495 * Custom types which only implement the Stringer/error interfaces via
496 a pointer receiver are optionally invoked when passing non-pointer
498 * Byte arrays and slices are dumped like the hexdump -C command which
499 includes offsets, byte values in hex, and ASCII output
501 The configuration options are controlled by an exported package global,
502 spew.Config. See ConfigState for options documentation.
504 See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
505 get the formatted result as a string.
507 func Dump(a ...interface{}) {
508 fdump(&Config, os.Stdout, a...)