// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package dwarf

import (
	
	
)

// DWARF debug info is split into a sequence of compilation units.
// Each unit has its own abbreviation table and address size.

type unit struct {
	base   Offset // byte offset of header within the aggregate info
	off    Offset // byte offset of data within the aggregate info
	data   []byte
	atable abbrevTable
	asize  int
	vers   int
	utype  uint8 // DWARF 5 unit type
	is64   bool  // True for 64-bit DWARF format
}

// Implement the dataFormat interface.

func ( *unit) () int {
	return .vers
}

func ( *unit) () (bool, bool) {
	return .is64, true
}

func ( *unit) () int {
	return .asize
}

func ( *Data) () ([]unit, error) {
	// Count units.
	 := 0
	 := makeBuf(, unknownFormat{}, "info", 0, .info)
	for len(.data) > 0 {
		,  := .unitLength()
		if  != Offset(uint32()) {
			.error("unit length overflow")
			break
		}
		.skip(int())
		if  > 0 {
			++
		}
	}
	if .err != nil {
		return nil, .err
	}

	// Again, this time writing them down.
	 = makeBuf(, unknownFormat{}, "info", 0, .info)
	 := make([]unit, )
	for  := range  {
		 := &[]
		.base = .off
		var  Offset
		if .err != nil {
			return nil, .err
		}
		for  == 0 {
			, .is64 = .unitLength()
		}
		 := .off
		 := .uint16()
		if  < 2 ||  > 5 {
			.error("unsupported DWARF version " + strconv.Itoa(int()))
			break
		}
		.vers = int()
		if  >= 5 {
			.utype = .uint8()
			.asize = int(.uint8())
		}
		var  uint64
		if .is64 {
			 = .uint64()
		} else {
			 = uint64(.uint32())
		}
		,  := .parseAbbrev(, .vers)
		if  != nil {
			if .err == nil {
				.err = 
			}
			break
		}
		.atable = 
		if  < 5 {
			.asize = int(.uint8())
		}

		switch .utype {
		case utSkeleton, utSplitCompile:
			.uint64() // unit ID
		case utType, utSplitType:
			.uint64()  // type signature
			if .is64 { // type offset
				.uint64()
			} else {
				.uint32()
			}
		}

		.off = .off
		.data = .bytes(int( - (.off - )))
	}
	if .err != nil {
		return nil, .err
	}
	return , nil
}

// offsetToUnit returns the index of the unit containing offset off.
// It returns -1 if no unit contains this offset.
func ( *Data) ( Offset) int {
	// Find the unit after off
	 := sort.Search(len(.unit), func( int) bool {
		return .unit[].off > 
	})
	if  == 0 {
		return -1
	}
	 := &.unit[-1]
	if .off <=  &&  < .off+Offset(len(.data)) {
		return  - 1
	}
	return -1
}