Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(795)

Delta Between Two Patch Sets: program/server/print.go

Issue 112270043: code review 112270043: ogle/server: provide type-aware printer for DWARF-typed... (Closed)
Left Patch Set: diff -r 836b304af90d https://code.google.com/p/ogle Created 9 years, 8 months ago
Right Patch Set: diff -r 836b304af90d https://code.google.com/p/ogle Created 9 years, 8 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « program/server/dwarf.go ('k') | program/server/server.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 // Copyright 2014 The Go Authors. All rights reserved. 1 // Copyright 2014 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 package server 5 package server
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "fmt" 9 "fmt"
10 "math" 10 "math"
11 11
12 "code.google.com/p/ogle/arch" 12 "code.google.com/p/ogle/arch"
13 "code.google.com/p/ogle/debug/dwarf" 13 "code.google.com/p/ogle/debug/dwarf"
14 ) 14 )
15 15
16 // Routines to print a value using DWARF type descriptions. 16 // Routines to print a value using DWARF type descriptions.
nigeltao 2014/07/15 04:14:41 s/Routines/Methods that don't take an implicit 'th
17 // TODO: Does this deserve its own package? It has no dependencies on Server. 17 // TODO: Does this deserve its own package? It has no dependencies on Server.
18 18
19 // A Printer pretty-prints a values in the target address space. 19 // A Printer pretty-prints a values in the target address space.
20 // It can be reused after each printing operation to avoid unnecessary 20 // It can be reused after each printing operation to avoid unnecessary
21 // allocations. However, it is not safe for concurrent access. 21 // allocations. However, it is not safe for concurrent access.
22 type Printer struct { 22 type Printer struct {
23 err error // Sticky error value. 23 err error // Sticky error value.
24 peeker Peeker 24 peeker Peeker
25 dwarf *dwarf.Data 25 dwarf *dwarf.Data
26 arch *arch.Architecture 26 arch *arch.Architecture
(...skipping 12 matching lines...) Expand all
39 39
40 // errorf sets the sticky error for the printer, if not already set. 40 // errorf sets the sticky error for the printer, if not already set.
41 func (p *Printer) errorf(format string, args ...interface{}) { 41 func (p *Printer) errorf(format string, args ...interface{}) {
42 if p.err != nil { 42 if p.err != nil {
43 return 43 return
44 } 44 }
45 p.err = fmt.Errorf(format, args...) 45 p.err = fmt.Errorf(format, args...)
46 } 46 }
47 47
48 // ok checks the error. If it is the first non-nil error encountered, 48 // ok checks the error. If it is the first non-nil error encountered,
49 // it is printed to printBuf, parenthesized for discimination, and remembered. 49 // it is printed to printBuf, parenthesized for discrimination, and remembered.
nigeltao 2014/07/15 04:14:40 Typo in "discrimination".
r 2014/07/15 04:56:51 Done.
50 func (p *Printer) ok(err error) bool { 50 func (p *Printer) ok(err error) bool {
51 » if p.err != nil && err != nil { 51 » if p.err == nil && err != nil {
nigeltao 2014/07/15 04:14:40 The first != should be ==.
r 2014/07/15 04:56:51 Done.
52 p.printf("(%s)", err) 52 p.printf("(%s)", err)
53 p.err = err 53 p.err = err
54 } 54 }
55 return p.err == nil 55 return p.err == nil
56 } 56 }
57 57
58 // peek reads len bytes at offset, leaving p.tmp with the data and sized appropr iately. 58 // peek reads len bytes at offset, leaving p.tmp with the data and sized appropr iately.
59 func (p *Printer) peek(offset uintptr, len int64) bool { 59 func (p *Printer) peek(offset uintptr, len int64) bool {
60 p.tmp = p.tmp[:len] 60 p.tmp = p.tmp[:len]
nigeltao 2014/07/15 04:14:40 What happens if you try to peek at a large array?
r 2014/07/15 04:56:50 it's never large. the only big thing we read this
61 return p.ok(p.peeker.peek(offset, p.tmp)) 61 return p.ok(p.peeker.peek(offset, p.tmp))
62 } 62 }
63 63
64 // Peeker is like a read that probes the remote address space. 64 // Peeker is like a read that probes the remote address space.
65 type Peeker interface { 65 type Peeker interface {
66 peek(offset uintptr, buf []byte) error 66 peek(offset uintptr, buf []byte) error
67 } 67 }
68 68
69 // NewPrinter returns a printer that can use the Peeker to access and print 69 // NewPrinter returns a printer that can use the Peeker to access and print
70 // values of the specified architecture described by the provided DWARF data. 70 // values of the specified architecture described by the provided DWARF data.
71 func NewPrinter(arch *arch.Architecture, dwarf *dwarf.Data, peeker Peeker) *Prin ter { 71 func NewPrinter(arch *arch.Architecture, dwarf *dwarf.Data, peeker Peeker) *Prin ter {
72 return &Printer{ 72 return &Printer{
73 peeker: peeker, 73 peeker: peeker,
74 arch: arch, 74 arch: arch,
75 dwarf: dwarf, 75 dwarf: dwarf,
76 visited: make(map[uintptr]bool), 76 visited: make(map[uintptr]bool),
77 tmp: make([]byte, 100), // Enough for a largish string. 77 tmp: make([]byte, 100), // Enough for a largish string.
nigeltao 2014/07/15 04:14:40 You could delete this line if you sized tmp on dem
r 2014/07/15 04:56:51 see above
78 } 78 }
79 } 79 }
80 80
81 // reset resets the Printer. It must be called before starting a new 81 // reset resets the Printer. It must be called before starting a new
82 // printing operation. 82 // printing operation.
83 func (p *Printer) reset() { 83 func (p *Printer) reset() {
84 p.err = nil 84 p.err = nil
85 p.printBuf.Reset() 85 p.printBuf.Reset()
86 // Just wipe the map rather than reallocating. It's almost always tiny. 86 // Just wipe the map rather than reallocating. It's almost always tiny.
87 for k := range p.visited { 87 for k := range p.visited {
(...skipping 26 matching lines...) Expand all
114 const ( 114 const (
115 locationAddr = 0x03 115 locationAddr = 0x03
116 ) 116 )
117 117
118 // decodeLocation decodes the dwarf data describing an address. 118 // decodeLocation decodes the dwarf data describing an address.
119 func (p *Printer) decodeLocation(data []byte) uintptr { 119 func (p *Printer) decodeLocation(data []byte) uintptr {
120 switch data[0] { 120 switch data[0] {
121 case locationAddr: 121 case locationAddr:
122 return uintptr(p.arch.Uintptr(data[1:])) 122 return uintptr(p.arch.Uintptr(data[1:]))
123 default: 123 default:
124 » » p.errorf("(unimplemented location type %#x)", data[0]) 124 » » p.errorf("unimplemented location type %#x", data[0])
nigeltao 2014/07/15 04:14:40 Drop the inner ()s?
r 2014/07/15 04:56:51 Done.
125 } 125 }
126 return 0 126 return 0
127 } 127 }
128 128
129 // SprintEntry returns the pretty-printed value of the item with the specified D WARF Entry and address. 129 // SprintEntry returns the pretty-printed value of the item with the specified D WARF Entry and address.
130 func (p *Printer) SprintEntry(entry *dwarf.Entry, addr uintptr) (string, error) { 130 func (p *Printer) SprintEntry(entry *dwarf.Entry, addr uintptr) (string, error) {
131 p.reset() 131 p.reset()
132 p.printEntryValueAt(entry, addr) 132 p.printEntryValueAt(entry, addr)
133 return p.printBuf.String(), p.err 133 return p.printBuf.String(), p.err
134 } 134 }
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 p.printf("%d", p.arch.UintN(p.tmp)) 192 p.printf("%d", p.arch.UintN(p.tmp))
193 } 193 }
194 case *dwarf.FloatType: 194 case *dwarf.FloatType:
195 if !p.peek(addr, typ.ByteSize) { 195 if !p.peek(addr, typ.ByteSize) {
196 return 196 return
197 } 197 }
198 switch typ.ByteSize { 198 switch typ.ByteSize {
199 case 4: 199 case 4:
200 p.printf("%g", math.Float32frombits(uint32(p.arch.UintN( p.tmp)))) 200 p.printf("%g", math.Float32frombits(uint32(p.arch.UintN( p.tmp))))
201 case 8: 201 case 8:
202 p.printf("%g", math.Float64frombits(p.arch.UintN(p.tmp)) ) 202 p.printf("%g", math.Float64frombits(p.arch.UintN(p.tmp)) )
nigeltao 2014/07/15 04:14:40 I don't know my hardware architectures that well..
r 2014/07/15 04:56:51 we'll find out, but i believe this is correct as w
203 default: 203 default:
204 p.errorf("unrecognized float size %d", typ.ByteSize) 204 p.errorf("unrecognized float size %d", typ.ByteSize)
205 } 205 }
206 case *dwarf.ComplexType: 206 case *dwarf.ComplexType:
207 if !p.peek(addr, typ.ByteSize) { 207 if !p.peek(addr, typ.ByteSize) {
208 return 208 return
209 } 209 }
210 switch typ.ByteSize { 210 switch typ.ByteSize {
211 case 8: 211 case 8:
212 r := math.Float32frombits(uint32(p.arch.UintN(p.tmp[:4]) )) 212 r := math.Float32frombits(uint32(p.arch.UintN(p.tmp[:4]) ))
213 i := math.Float32frombits(uint32(p.arch.UintN(p.tmp[4:8] ))) 213 i := math.Float32frombits(uint32(p.arch.UintN(p.tmp[4:8] )))
214 p.printf("%g", complex(r, i)) 214 p.printf("%g", complex(r, i))
215 case 16: 215 case 16:
216 r := math.Float64frombits(p.arch.UintN(p.tmp[:8])) 216 r := math.Float64frombits(p.arch.UintN(p.tmp[:8]))
217 i := math.Float64frombits(p.arch.UintN(p.tmp[8:16])) 217 i := math.Float64frombits(p.arch.UintN(p.tmp[8:16]))
218 p.printf("%g", complex(r, i)) 218 p.printf("%g", complex(r, i))
219 default: 219 default:
220 p.errorf("unrecognized complex size %d", typ.ByteSize) 220 p.errorf("unrecognized complex size %d", typ.ByteSize)
221 } 221 }
222 case *dwarf.StructType: 222 case *dwarf.StructType:
223 p.visited[addr] = true 223 p.visited[addr] = true
224 if typ.Kind != "struct" { 224 if typ.Kind != "struct" {
225 // Could be "class" or "union". 225 // Could be "class" or "union".
226 p.errorf("can't handle struct type %s", typ.Kind) 226 p.errorf("can't handle struct type %s", typ.Kind)
227 return 227 return
228 } 228 }
229 p.printf("%s {", typ.String()) 229 p.printf("%s {", typ.String())
230 » » first := true 230 » » for i, field := range typ.Field {
231 » » for _, field := range typ.Field { 231 » » » if i != 0 {
232 » » » if !first {
233 p.printf(", ") 232 p.printf(", ")
234 } 233 }
235 first = false
236 p.printValueAt(field.Type, addr+uintptr(field.ByteOffset )) 234 p.printValueAt(field.Type, addr+uintptr(field.ByteOffset ))
237 } 235 }
238 p.printf("}") 236 p.printf("}")
239 case *dwarf.ArrayType: 237 case *dwarf.ArrayType:
240 p.printArrayAt(typ, addr) 238 p.printArrayAt(typ, addr)
241 case *dwarf.MapType: 239 case *dwarf.MapType:
242 p.visited[addr] = true 240 p.visited[addr] = true
243 p.printMapAt(typ, addr) 241 p.printMapAt(typ, addr)
244 case *dwarf.SliceType: 242 case *dwarf.SliceType:
245 p.visited[addr] = true 243 p.visited[addr] = true
246 p.printSliceAt(typ, addr) 244 p.printSliceAt(typ, addr)
247 case *dwarf.StringType: 245 case *dwarf.StringType:
248 p.printStringAt(typ, addr) 246 p.printStringAt(typ, addr)
249 case *dwarf.TypedefType: 247 case *dwarf.TypedefType:
250 p.errorf("unimplemented typedef type %T %v", typ, typ) 248 p.errorf("unimplemented typedef type %T %v", typ, typ)
nigeltao 2014/07/15 04:14:41 Is the "%T" useful? Isn't it just "*dwarf.TypedefT
r 2014/07/15 04:56:50 %T tells us what the dwarf type is. %s shows us wh
251 default: 249 default:
252 // TODO: chan func interface 250 // TODO: chan func interface
253 p.errorf("unimplemented type %v", typ) 251 p.errorf("unimplemented type %v", typ)
254 } 252 }
255 } 253 }
256 254
257 func (p *Printer) printArrayAt(typ *dwarf.ArrayType, addr uintptr) { 255 func (p *Printer) printArrayAt(typ *dwarf.ArrayType, addr uintptr) {
258 if !p.peek(addr, typ.ByteSize) {
259 p.errorf("array has no defined size")
nigeltao 2014/07/15 04:14:40 I might be misunderstanding the code, but "no defi
r 2014/07/15 04:56:51 This code is wrong anyway. There's no point in rea
260 return
261 }
262 elemType := typ.Type 256 elemType := typ.Type
263 length := typ.Count 257 length := typ.Count
264 stride := typ.StrideBitSize 258 stride := typ.StrideBitSize
265 if stride > 0 { 259 if stride > 0 {
266 stride /= 8 260 stride /= 8
267 } else { 261 } else {
268 stride = p.sizeof(elemType) 262 stride = p.sizeof(elemType)
269 if stride < 0 { 263 if stride < 0 {
270 » » » p.errorf("array elements have no defined size") 264 » » » p.errorf("array elements have no known size")
271 } 265 }
272 } 266 }
273 p.printf("%s{", typ) 267 p.printf("%s{", typ)
274 » first := true 268 » n := length
275 » for i := int64(0); i < length; i++ { 269 » if n > 100 {
276 » » if !first { 270 » » n = 100 // TODO: Have a way to control this?
nigeltao 2014/07/15 04:14:40 This could just be "if i != 0 {" and you could the
r 2014/07/15 04:56:50 Done.
r 2014/07/15 04:56:51 Done.
271 » }
272 » for i := int64(0); i < n; i++ {
273 » » if i != 0 {
277 p.printf(", ") 274 p.printf(", ")
278 } 275 }
279 first = false
280 p.printValueAt(elemType, addr) 276 p.printValueAt(elemType, addr)
281 addr += uintptr(stride) // TODO: Alignment and padding - not giv en by Type 277 addr += uintptr(stride) // TODO: Alignment and padding - not giv en by Type
278 }
279 if n < length {
280 p.printf(", ...")
282 } 281 }
283 p.printf("}") 282 p.printf("}")
284 } 283 }
285 284
286 // TODO: Unimplemented. 285 // TODO: Unimplemented.
287 func (p *Printer) printMapAt(typ *dwarf.MapType, addr uintptr) { 286 func (p *Printer) printMapAt(typ *dwarf.MapType, addr uintptr) {
288 // Maps are pointers to a struct type. 287 // Maps are pointers to a struct type.
289 structType := typ.Type.(*dwarf.PtrType).Type.(*dwarf.StructType) 288 structType := typ.Type.(*dwarf.PtrType).Type.(*dwarf.StructType)
290 // Indirect through the pointer. 289 // Indirect through the pointer.
291 if !p.peek(addr, int64(p.arch.PointerSize)) { 290 if !p.peek(addr, int64(p.arch.PointerSize)) {
292 return 291 return
293 } 292 }
294 addr = uintptr(p.arch.Uintptr(p.tmp[:p.arch.PointerSize])) 293 addr = uintptr(p.arch.Uintptr(p.tmp[:p.arch.PointerSize]))
295 // Now read the struct. 294 // Now read the struct.
296 if !p.peek(addr, structType.ByteSize) { 295 if !p.peek(addr, structType.ByteSize) {
297 return 296 return
298 } 297 }
299 // TODO: unimplemented. Hard. 298 // TODO: unimplemented. Hard.
300 countField := structType.Field[0] 299 countField := structType.Field[0]
301 p.printf("%s with ", typ) 300 p.printf("%s with ", typ)
302 p.printValueAt(countField.Type, addr+uintptr(countField.ByteOffset)) 301 p.printValueAt(countField.Type, addr+uintptr(countField.ByteOffset))
303 p.printf(" elements") 302 p.printf(" elements")
304 } 303 }
305 304
306 func (p *Printer) printSliceAt(typ *dwarf.SliceType, addr uintptr) { 305 func (p *Printer) printSliceAt(typ *dwarf.SliceType, addr uintptr) {
307 // Slices look like a struct with fields array *elemtype, len uint32/64, cap uint32/64. 306 // Slices look like a struct with fields array *elemtype, len uint32/64, cap uint32/64.
308 // BUG: Slice header appears to have fields with ByteSize == 0 307 // BUG: Slice header appears to have fields with ByteSize == 0
309 if !p.peek(addr, typ.ByteSize) { 308 if !p.peek(addr, typ.ByteSize) {
310 » » p.errorf("slice has no defined size") 309 » » p.errorf("slice header has no known size")
311 return 310 return
312 } 311 }
313 lo := typ.Field[0].ByteOffset 312 lo := typ.Field[0].ByteOffset
314 hi := lo + int64(p.arch.PointerSize) 313 hi := lo + int64(p.arch.PointerSize)
315 ptr := uintptr(p.arch.UintN(p.tmp[lo:hi])) 314 ptr := uintptr(p.arch.UintN(p.tmp[lo:hi]))
316 lo = typ.Field[1].ByteOffset 315 lo = typ.Field[1].ByteOffset
317 hi = lo + int64(p.arch.IntSize) 316 hi = lo + int64(p.arch.IntSize)
318 length := p.arch.UintN(p.tmp[lo:hi]) 317 length := p.arch.UintN(p.tmp[lo:hi])
319 // Capacity is unused here. 318 // Capacity is unused here.
320 elemType := typ.ElemType 319 elemType := typ.ElemType
321 size := p.sizeof(elemType) 320 size := p.sizeof(elemType)
322 if size < 0 { 321 if size < 0 {
323 return 322 return
324 } 323 }
325 p.printf("%s{", typ) 324 p.printf("%s{", typ)
326 first := true
327 for i := uint64(0); i < length; i++ { 325 for i := uint64(0); i < length; i++ {
328 » » if !first { 326 » » if i != 0 {
329 p.printf(", ") 327 p.printf(", ")
330 } 328 }
331 first = false
332 p.printValueAt(elemType, ptr) 329 p.printValueAt(elemType, ptr)
333 ptr += uintptr(size) // TODO: Alignment and padding - not given by Type 330 ptr += uintptr(size) // TODO: Alignment and padding - not given by Type
334 } 331 }
335 p.printf("}") 332 p.printf("}")
336 } 333 }
337 334
338 func (p *Printer) printStringAt(typ *dwarf.StringType, addr uintptr) { 335 func (p *Printer) printStringAt(typ *dwarf.StringType, addr uintptr) {
339 // Strings look like a struct with fields array *elemtype, len uint64. 336 // Strings look like a struct with fields array *elemtype, len uint64.
340 // TODO uint64 on 386 too? 337 // TODO uint64 on 386 too?
341 if !p.peek(addr, typ.ByteSize) { 338 if !p.peek(addr, typ.ByteSize) {
342 » » p.errorf("string has no defined size") 339 » » p.errorf("string header has no known size")
343 return 340 return
344 } 341 }
345 // BUG: String header appears to have fields with ByteSize == 0 342 // BUG: String header appears to have fields with ByteSize == 0
346 lo := typ.Field[0].ByteOffset 343 lo := typ.Field[0].ByteOffset
347 hi := lo + int64(p.arch.PointerSize) 344 hi := lo + int64(p.arch.PointerSize)
348 ptr := p.arch.UintN(p.tmp[lo:hi]) 345 ptr := p.arch.UintN(p.tmp[lo:hi])
349 lo = typ.Field[1].ByteOffset 346 lo = typ.Field[1].ByteOffset
350 hi = lo + int64(p.arch.IntSize) // TODO? 347 hi = lo + int64(p.arch.IntSize) // TODO?
351 length := p.arch.UintN(p.tmp[lo:hi]) 348 length := p.arch.UintN(p.tmp[lo:hi])
352 if length > uint64(cap(p.tmp)) { 349 if length > uint64(cap(p.tmp)) {
353 if p.peek(uintptr(ptr), int64(cap(p.tmp))) { 350 if p.peek(uintptr(ptr), int64(cap(p.tmp))) {
354 p.printf("%q...", p.tmp) 351 p.printf("%q...", p.tmp)
355 } 352 }
356 } else { 353 } else {
357 if p.peek(uintptr(ptr), int64(length)) { 354 if p.peek(uintptr(ptr), int64(length)) {
358 p.printf("%q", p.tmp[:length]) 355 p.printf("%q", p.tmp[:length])
359 } 356 }
360 } 357 }
361 } 358 }
362 359
363 // sizeof returns the byte size of the type. It returns -1 if no size can be fou nd. 360 // sizeof returns the byte size of the type. It returns -1 if no size can be fou nd.
364 func (p *Printer) sizeof(typ dwarf.Type) int64 { 361 func (p *Printer) sizeof(typ dwarf.Type) int64 {
365 size := typ.Size() // Will be -1 if ByteSize is not set. 362 size := typ.Size() // Will be -1 if ByteSize is not set.
366 if size >= 0 { 363 if size >= 0 {
367 return size 364 return size
368 } 365 }
369 switch typ.(type) { 366 switch typ.(type) {
370 default:
nigeltao 2014/07/15 04:14:41 You could drop the default case: switch typ.(type
r 2014/07/15 04:56:51 Done.
371 p.errorf("unknown size for %s", typ.String())
nigeltao 2014/07/15 04:14:40 Add size = -1 after this. Or drop the default case
nigeltao 2014/07/15 04:14:40 The ".String()" is unnecessary.
r 2014/07/15 04:56:51 Done.
r 2014/07/15 04:56:51 Done.
372 case *dwarf.PtrType: 367 case *dwarf.PtrType:
373 » » size = int64(p.arch.PointerSize) 368 » » // This is the only one we know of, but more may arise.
374 » } 369 » » return int64(p.arch.PointerSize)
375 » return size 370 » }
376 } 371 » p.errorf("unknown size for %s", typ)
372 » return -1
373 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b