func()

in libgo/go/debug/dwarf/entry.go [409:790]


func (b *buf) entry(cu *Entry, atab abbrevTable, ubase Offset, vers int) *Entry {
	off := b.off
	id := uint32(b.uint())
	if id == 0 {
		return &Entry{}
	}
	a, ok := atab[id]
	if !ok {
		b.error("unknown abbreviation table index")
		return nil
	}
	e := &Entry{
		Offset:   off,
		Tag:      a.tag,
		Children: a.children,
		Field:    make([]Field, len(a.field)),
	}

	// If we are currently parsing the compilation unit,
	// we can't evaluate Addrx or Strx until we've seen the
	// relevant base entry.
	type delayed struct {
		idx int
		off uint64
		fmt format
	}
	var delay []delayed

	resolveStrx := func(strBase, off uint64) string {
		off += strBase
		if uint64(int(off)) != off {
			b.error("DW_FORM_strx offset out of range")
		}

		b1 := makeBuf(b.dwarf, b.format, "str_offsets", 0, b.dwarf.strOffsets)
		b1.skip(int(off))
		is64, _ := b.format.dwarf64()
		if is64 {
			off = b1.uint64()
		} else {
			off = uint64(b1.uint32())
		}
		if b1.err != nil {
			b.err = b1.err
			return ""
		}
		if uint64(int(off)) != off {
			b.error("DW_FORM_strx indirect offset out of range")
		}
		b1 = makeBuf(b.dwarf, b.format, "str", 0, b.dwarf.str)
		b1.skip(int(off))
		val := b1.string()
		if b1.err != nil {
			b.err = b1.err
		}
		return val
	}

	resolveRnglistx := func(rnglistsBase, off uint64) uint64 {
		is64, _ := b.format.dwarf64()
		if is64 {
			off *= 8
		} else {
			off *= 4
		}
		off += rnglistsBase
		if uint64(int(off)) != off {
			b.error("DW_FORM_rnglistx offset out of range")
		}

		b1 := makeBuf(b.dwarf, b.format, "rnglists", 0, b.dwarf.rngLists)
		b1.skip(int(off))
		if is64 {
			off = b1.uint64()
		} else {
			off = uint64(b1.uint32())
		}
		if b1.err != nil {
			b.err = b1.err
			return 0
		}
		if uint64(int(off)) != off {
			b.error("DW_FORM_rnglistx indirect offset out of range")
		}
		return rnglistsBase + off
	}

	for i := range e.Field {
		e.Field[i].Attr = a.field[i].attr
		e.Field[i].Class = a.field[i].class
		fmt := a.field[i].fmt
		if fmt == formIndirect {
			fmt = format(b.uint())
			e.Field[i].Class = formToClass(fmt, a.field[i].attr, vers, b)
		}
		var val interface{}
		switch fmt {
		default:
			b.error("unknown entry attr format 0x" + strconv.FormatInt(int64(fmt), 16))

		// address
		case formAddr:
			val = b.addr()
		case formAddrx, formAddrx1, formAddrx2, formAddrx3, formAddrx4:
			var off uint64
			switch fmt {
			case formAddrx:
				off = b.uint()
			case formAddrx1:
				off = uint64(b.uint8())
			case formAddrx2:
				off = uint64(b.uint16())
			case formAddrx3:
				off = uint64(b.uint24())
			case formAddrx4:
				off = uint64(b.uint32())
			}
			if b.dwarf.addr == nil {
				b.error("DW_FORM_addrx with no .debug_addr section")
			}
			if b.err != nil {
				return nil
			}

			// We have to adjust by the offset of the
			// compilation unit. This won't work if the
			// program uses Reader.Seek to skip over the
			// unit. Not much we can do about that.
			var addrBase int64
			if cu != nil {
				addrBase, _ = cu.Val(AttrAddrBase).(int64)
			} else if a.tag == TagCompileUnit {
				delay = append(delay, delayed{i, off, formAddrx})
				break
			}

			var err error
			val, err = b.dwarf.debugAddr(b.format, uint64(addrBase), off)
			if err != nil {
				if b.err == nil {
					b.err = err
				}
				return nil
			}

		// block
		case formDwarfBlock1:
			val = b.bytes(int(b.uint8()))
		case formDwarfBlock2:
			val = b.bytes(int(b.uint16()))
		case formDwarfBlock4:
			val = b.bytes(int(b.uint32()))
		case formDwarfBlock:
			val = b.bytes(int(b.uint()))

		// constant
		case formData1:
			val = int64(b.uint8())
		case formData2:
			val = int64(b.uint16())
		case formData4:
			val = int64(b.uint32())
		case formData8:
			val = int64(b.uint64())
		case formData16:
			val = b.bytes(16)
		case formSdata:
			val = int64(b.int())
		case formUdata:
			val = int64(b.uint())
		case formImplicitConst:
			val = a.field[i].val

		// flag
		case formFlag:
			val = b.uint8() == 1
		// New in DWARF 4.
		case formFlagPresent:
			// The attribute is implicitly indicated as present, and no value is
			// encoded in the debugging information entry itself.
			val = true

		// reference to other entry
		case formRefAddr:
			vers := b.format.version()
			if vers == 0 {
				b.error("unknown version for DW_FORM_ref_addr")
			} else if vers == 2 {
				val = Offset(b.addr())
			} else {
				is64, known := b.format.dwarf64()
				if !known {
					b.error("unknown size for DW_FORM_ref_addr")
				} else if is64 {
					val = Offset(b.uint64())
				} else {
					val = Offset(b.uint32())
				}
			}
		case formRef1:
			val = Offset(b.uint8()) + ubase
		case formRef2:
			val = Offset(b.uint16()) + ubase
		case formRef4:
			val = Offset(b.uint32()) + ubase
		case formRef8:
			val = Offset(b.uint64()) + ubase
		case formRefUdata:
			val = Offset(b.uint()) + ubase

		// string
		case formString:
			val = b.string()
		case formStrp, formLineStrp:
			var off uint64 // offset into .debug_str
			is64, known := b.format.dwarf64()
			if !known {
				b.error("unknown size for DW_FORM_strp/line_strp")
			} else if is64 {
				off = b.uint64()
			} else {
				off = uint64(b.uint32())
			}
			if uint64(int(off)) != off {
				b.error("DW_FORM_strp/line_strp offset out of range")
			}
			if b.err != nil {
				return nil
			}
			var b1 buf
			if fmt == formStrp {
				b1 = makeBuf(b.dwarf, b.format, "str", 0, b.dwarf.str)
			} else {
				if len(b.dwarf.lineStr) == 0 {
					b.error("DW_FORM_line_strp with no .debug_line_str section")
				}
				b1 = makeBuf(b.dwarf, b.format, "line_str", 0, b.dwarf.lineStr)
			}
			b1.skip(int(off))
			val = b1.string()
			if b1.err != nil {
				b.err = b1.err
				return nil
			}
		case formStrx, formStrx1, formStrx2, formStrx3, formStrx4:
			var off uint64
			switch fmt {
			case formStrx:
				off = b.uint()
			case formStrx1:
				off = uint64(b.uint8())
			case formStrx2:
				off = uint64(b.uint16())
			case formStrx3:
				off = uint64(b.uint24())
			case formStrx4:
				off = uint64(b.uint32())
			}
			if len(b.dwarf.strOffsets) == 0 {
				b.error("DW_FORM_strx with no .debug_str_offsets section")
			}
			is64, known := b.format.dwarf64()
			if !known {
				b.error("unknown offset size for DW_FORM_strx")
			}
			if b.err != nil {
				return nil
			}
			if is64 {
				off *= 8
			} else {
				off *= 4
			}

			// We have to adjust by the offset of the
			// compilation unit. This won't work if the
			// program uses Reader.Seek to skip over the
			// unit. Not much we can do about that.
			var strBase int64
			if cu != nil {
				strBase, _ = cu.Val(AttrStrOffsetsBase).(int64)
			} else if a.tag == TagCompileUnit {
				delay = append(delay, delayed{i, off, formStrx})
				break
			}

			val = resolveStrx(uint64(strBase), off)

		case formStrpSup:
			is64, known := b.format.dwarf64()
			if !known {
				b.error("unknown size for DW_FORM_strp_sup")
			} else if is64 {
				val = b.uint64()
			} else {
				val = b.uint32()
			}

		// lineptr, loclistptr, macptr, rangelistptr
		// New in DWARF 4, but clang can generate them with -gdwarf-2.
		// Section reference, replacing use of formData4 and formData8.
		case formSecOffset, formGnuRefAlt, formGnuStrpAlt:
			is64, known := b.format.dwarf64()
			if !known {
				b.error("unknown size for form 0x" + strconv.FormatInt(int64(fmt), 16))
			} else if is64 {
				val = int64(b.uint64())
			} else {
				val = int64(b.uint32())
			}

		// exprloc
		// New in DWARF 4.
		case formExprloc:
			val = b.bytes(int(b.uint()))

		// reference
		// New in DWARF 4.
		case formRefSig8:
			// 64-bit type signature.
			val = b.uint64()
		case formRefSup4:
			val = b.uint32()
		case formRefSup8:
			val = b.uint64()

		// loclist
		case formLoclistx:
			val = b.uint()

		// rnglist
		case formRnglistx:
			off := b.uint()

			// We have to adjust by the rnglists_base of
			// the compilation unit. This won't work if
			// the program uses Reader.Seek to skip over
			// the unit. Not much we can do about that.
			var rnglistsBase int64
			if cu != nil {
				rnglistsBase, _ = cu.Val(AttrRnglistsBase).(int64)
			} else if a.tag == TagCompileUnit {
				delay = append(delay, delayed{i, off, formRnglistx})
				break
			}

			val = resolveRnglistx(uint64(rnglistsBase), off)
		}

		e.Field[i].Val = val
	}
	if b.err != nil {
		return nil
	}

	for _, del := range delay {
		switch del.fmt {
		case formAddrx:
			addrBase, _ := e.Val(AttrAddrBase).(int64)
			val, err := b.dwarf.debugAddr(b.format, uint64(addrBase), del.off)
			if err != nil {
				b.err = err
				return nil
			}
			e.Field[del.idx].Val = val
		case formStrx:
			strBase, _ := e.Val(AttrStrOffsetsBase).(int64)
			e.Field[del.idx].Val = resolveStrx(uint64(strBase), del.off)
			if b.err != nil {
				return nil
			}
		case formRnglistx:
			rnglistsBase, _ := e.Val(AttrRnglistsBase).(int64)
			e.Field[del.idx].Val = resolveRnglistx(uint64(rnglistsBase), del.off)
			if b.err != nil {
				return nil
			}
		}
	}

	return e
}