Files
blacktop 8e6f2c554b chore: modernize to 1.26
Refactor string concatenation to use strings.Builder for improved performance in multiple files
2026-02-12 10:02:01 -07:00

1061 lines
22 KiB
Go

package ctf
import (
"bytes"
"encoding/json"
"fmt"
"strconv"
"strings"
"text/tabwriter"
)
type Type interface {
ID() int
Name() string
Info() Info
ParentID() int
Type() string
String() string
Dump() string
}
type Integer struct {
id int
name string
info Info
encoding intEncoding
}
func (i *Integer) ID() int {
return i.id
}
func (i *Integer) Name() string {
return i.name
}
func (i *Integer) Info() Info {
return i.info
}
func (i *Integer) Encoding() string {
return i.encoding.Encoding().String()
}
func (i *Integer) Offset() uint32 {
return i.encoding.Offset()
}
func (i *Integer) Bits() uint32 {
return i.encoding.Bits()
}
func (i *Integer) ParentID() int {
return 0
}
func (i *Integer) Type() string {
return i.name
}
func (i *Integer) String() string {
return i.name
}
func (i *Integer) Dump() string {
return fmt.Sprintf("%s %s %s encoding=%s offset=%d bits=%d\n",
isRootIDFmtStr(i.info.IsRoot(), i.id),
i.info.Kind(),
i.name,
i.encoding.Encoding(),
i.encoding.Offset(),
i.encoding.Bits(),
)
}
func (i *Integer) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Info Info `json:"info,omitempty"`
Encoding intEncoding `json:"encoding,omitempty"`
}{
ID: i.id,
Name: i.name,
Info: i.info,
Encoding: i.encoding,
})
}
type Float struct {
id int
name string
info Info
encoding floatEncoding
}
func (f *Float) ID() int {
return f.id
}
func (f *Float) Name() string {
return f.name
}
func (f *Float) Info() Info {
return f.info
}
func (f *Float) Encoding() string {
return f.encoding.Encoding().String()
}
func (f *Float) Offset() uint32 {
return f.encoding.Offset()
}
func (f *Float) Bits() uint32 {
return f.encoding.Bits()
}
func (f *Float) ParentID() int {
return 0
}
func (f *Float) Type() string {
return f.name
}
func (f *Float) String() string {
return f.name
}
func (f *Float) Dump() string {
return fmt.Sprintf("%s %s %s encoding=%s offset=%d bits=%d",
isRootIDFmtStr(f.info.IsRoot(), f.id),
f.info.Kind(),
f.name,
f.encoding.Encoding(),
f.encoding.Offset(),
f.encoding.Bits(),
)
}
func (f *Float) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Info Info `json:"info,omitempty"`
Encoding floatEncoding `json:"encoding,omitempty"`
}{
ID: f.id,
Name: f.name,
Info: f.info,
Encoding: f.encoding,
})
}
type Array struct {
id int
name string
info Info
array
lookupFn func(int) Type
}
func (a *Array) ID() int {
return a.id
}
func (a *Array) Name() string {
if a.name == "(anon)" {
return ""
}
return " " + a.name
}
func (a *Array) Info() Info {
return a.info
}
func (a *Array) Index() string {
if t := a.lookupFn(int(a.array.Index)); t != nil {
return t.Type()
}
return "<type not found>"
}
func (a *Array) Contents() string {
if t := a.lookupFn(int(a.array.Contents)); t != nil {
return t.Type()
}
return "<type not found>"
}
func (a *Array) ParentID() int {
return 0
}
func (a *Array) Type() string {
return strings.TrimSuffix(a.String(), ";")
}
func (a *Array) String() string {
return fmt.Sprintf(
"%s%s[%d];",
a.Contents(),
a.Name(),
a.NumElements,
)
}
func (a *Array) Dump() string {
return fmt.Sprintf("%s %s %s content: %d index: %d nelems: %d",
isRootIDFmtStr(a.info.IsRoot(), a.id),
a.info.Kind(),
a.name,
a.array.Contents,
a.array.Index,
a.array.NumElements,
)
}
func (a *Array) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Info Info `json:"info,omitempty"`
ContentsID uint `json:"contents_id,omitempty"` /* reference to type of array contents */
Contents string `json:"contents,omitempty"` /* reference to type of array contents */
IndexID uint `json:"index_id,omitempty"` /* reference to type of array index */
IndexType string `json:"index_type,omitempty"` /* reference to type of array index */
NumElements uint32 `json:"num_elements,omitempty"` /* number of elements */
}{
ID: a.id,
Name: a.name,
Info: a.info,
ContentsID: uint(a.array.Contents),
Contents: a.Contents(),
IndexID: uint(a.array.Index),
IndexType: a.Index(),
NumElements: a.array.NumElements,
})
}
type Function struct {
id int
name string
info Info
ret uint
args []uint32
lookupFn func(int) Type
}
type funcArg struct {
ID int `json:"id,omitempty"`
Type string `json:"type,omitempty"`
}
func (f *Function) ID() int {
return f.id
}
func (f *Function) Name() string {
return f.name
}
func (f *Function) Info() Info {
return f.info
}
func (f *Function) Return() string {
if t := f.lookupFn(int(f.ret)); t != nil {
return t.Type()
}
return "<return type not found>"
}
func (f *Function) Args() string {
var argStrs []string
for idx, arg := range f.args {
if t := f.lookupFn(int(arg)); t != nil {
argStrs = append(argStrs, t.Type())
} else {
return fmt.Sprintf("<arg%d type not found>", idx)
}
}
return strings.Join(argStrs, ", ")
}
func (f *Function) ParentID() int {
return 0
}
func (f *Function) Type() string {
return strings.TrimSuffix(f.String(), ";")
}
func (f *Function) String() string {
return fmt.Sprintf(
"%s %s(%s);",
f.Return(),
f.name,
f.Args(),
)
}
func (f *Function) Dump() string {
var fdump string
fdump = fmt.Sprintf("%s %s %s returns: %d args: (",
isRootIDFmtStr(f.info.IsRoot(), f.id),
f.info.Kind(),
f.name,
f.ret,
)
var sargs []string
for _, a := range f.args {
sargs = append(sargs, strconv.Itoa(int(a)))
}
fdump += fmt.Sprintf("%s)", strings.Join(sargs, ","))
return fdump
}
func (f *Function) MarshalJSON() ([]byte, error) {
var args []funcArg
for idx, arg := range f.args {
if t := f.lookupFn(int(arg)); t != nil {
args = append(args, funcArg{
ID: int(arg),
Type: t.Type(),
})
} else {
args = append(args, funcArg{
ID: int(arg),
Type: fmt.Sprintf("<arg%d type ref %d not found>", idx, arg),
})
}
}
return json.Marshal(&struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Info Info `json:"info,omitempty"`
ReturnID uint `json:"return_id,omitempty"`
Return string `json:"return,omitempty"`
Arguments []funcArg `json:"arguments,omitempty"`
}{
ID: f.id,
Name: f.name,
Info: f.info,
ReturnID: uint(f.ret),
Return: f.Return(),
Arguments: args,
})
}
type Member struct {
parent int
name string
offset uint64
reference uint
lookupFn func(int) Type
}
func (m Member) ParentID() int {
return m.parent
}
func (m Member) Name() string {
return m.name
}
func (m Member) Type() string {
if t := m.lookupFn(int(m.reference)); t != nil {
return t.Type()
}
return "<member type not found>"
}
func (m Member) Offset() uint64 {
return m.offset
}
func (m Member) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Type string `json:"type,omitempty"`
Offset uint64 `json:"offset"`
}{
ID: int(m.reference),
Name: m.name,
Type: m.Type(),
Offset: m.offset,
})
}
type Struct struct {
id int
name string
info Info
size uint64
Fields []Member
lookupFn func(int) Type
}
func (s *Struct) ID() int {
return s.id
}
func (s *Struct) Name() string {
if s.name == "(anon)" {
return ""
}
return s.name
}
func (s *Struct) Info() Info {
return s.info
}
func (s *Struct) ParentID() int {
return 0
}
func (s *Struct) Size() uint64 {
return s.size
}
func (s *Struct) Type() string {
if s.name == "(anon)" {
return strings.TrimSuffix(s.String(), ";")
}
return "struct " + s.Name()
}
func (s *Struct) String() string {
buf := bytes.NewBufferString("")
w := tabwriter.NewWriter(buf, 0, 0, 1, ' ', 0)
fmt.Fprintf(w,
"struct %s {\t\t// (%d bytes)\n",
s.Name(),
s.size,
)
for _, f := range s.Fields {
t := s.lookupFn(int(f.reference))
if t != nil && t.Info().Kind() == ARRAY {
fmt.Fprintf(w, " %s\t%s[%d];\t// off=%#x\n",
t.(*Array).Contents(),
f.name,
t.(*Array).NumElements,
f.offset,
)
} else {
fmt.Fprintf(w, " %s\t%s;\t// off=%#x\n",
f.Type(),
f.name,
f.offset,
)
}
}
fmt.Fprintf(w, "};")
w.Flush()
return buf.String()
}
func (s *Struct) Dump() string {
buf := bytes.NewBufferString("")
w := tabwriter.NewWriter(buf, 0, 0, 1, ' ', 0)
fmt.Fprintf(w, "%s %s %s (%d bytes)\n",
isRootIDFmtStr(s.info.IsRoot(), s.id),
s.info.Kind(),
s.name,
s.size,
)
for _, f := range s.Fields {
fmt.Fprintf(w, " %s\ttype=%d\toff=%#x\n",
f.Name(),
f.reference,
f.offset,
)
}
w.Flush()
return buf.String()
}
func (s *Struct) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Info Info `json:"info,omitempty"`
Size uint64 `json:"size,omitempty"`
Fields []Member `json:"fields,omitempty"`
}{
ID: s.id,
Name: s.name,
Info: s.info,
Size: s.size,
Fields: s.Fields,
})
}
type Union struct {
id int
name string
info Info
size uint64
Fields []Member
lookupFn func(int) Type
}
func (s *Union) ID() int {
return s.id
}
func (s *Union) Name() string {
if s.name == "(anon)" {
return ""
}
return s.name
}
func (s *Union) Info() Info {
return s.info
}
func (s *Union) ParentID() int {
return 0
}
func (s *Union) Size() uint64 {
return s.size
}
func (s *Union) Type() string {
return "union " + s.name
}
func (s *Union) String() string {
buf := bytes.NewBufferString("")
w := tabwriter.NewWriter(buf, 0, 0, 1, ' ', 0)
fmt.Fprintf(w,
"union %s {\t\t// (%d bytes)\n",
s.Name(),
s.size,
)
for _, f := range s.Fields {
t := s.lookupFn(int(f.reference))
if t != nil && t.Info().Kind() == ARRAY {
fmt.Fprintf(w, " %s\t%s[%d];\n",
t.(*Array).Contents(),
f.name,
t.(*Array).NumElements,
)
} else {
fmt.Fprintf(w, " %s\t%s;\n",
f.Type(),
f.name,
)
}
}
fmt.Fprintf(w, "};")
w.Flush()
return buf.String()
}
func (s *Union) Dump() string {
var sdump string
sdump = fmt.Sprintf("%s %s %s (%d bytes)\n",
isRootIDFmtStr(s.info.IsRoot(), s.id),
s.info.Kind(),
s.name,
s.size,
)
for _, f := range s.Fields {
sdump += fmt.Sprintf("\t%s type=%d off=%#x\n",
f.Name(),
f.reference,
f.offset,
)
}
return sdump
}
func (s *Union) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Info Info `json:"info,omitempty"`
Size uint64 `json:"size,omitempty"`
Fields []Member `json:"fields,omitempty"`
}{
ID: s.id,
Name: s.name,
Info: s.info,
Size: s.size,
Fields: s.Fields,
})
}
type enumField struct {
Name string `json:"name,omitempty"`
Value int32 `json:"value,omitempty"`
}
type Enum struct {
id int
name string
info Info
Fields []enumField
}
func (e *Enum) ID() int {
return e.id
}
func (e *Enum) Name() string {
return e.name
}
func (e *Enum) Info() Info {
return e.info
}
func (e *Enum) ParentID() int {
return 0
}
func (e *Enum) Type() string { return "enum " + e.name }
func (e *Enum) String() string {
var eout strings.Builder
eout.WriteString(fmt.Sprintf("enum %s {\n", e.name))
for _, f := range e.Fields {
eout.WriteString(fmt.Sprintf("\t%s = %d\n",
f.Name,
f.Value,
))
}
eout.WriteString("};")
return eout.String()
}
func (e *Enum) Dump() string {
var edump string
edump = fmt.Sprintf("%s %s %s\n",
isRootIDFmtStr(e.info.IsRoot(), e.id),
e.info.Kind(),
e.name,
)
for _, f := range e.Fields {
edump += fmt.Sprintf("\t%s = %d\n",
f.Name,
f.Value,
)
}
return edump
}
func (e *Enum) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Info Info `json:"info,omitempty"`
Fields []enumField `json:"fields,omitempty"`
}{
ID: e.id,
Name: e.name,
Info: e.info,
Fields: e.Fields,
})
}
type Forward struct {
id int
name string
info Info
}
func (f *Forward) ID() int {
return f.id
}
func (f *Forward) Name() string {
return f.name
}
func (f *Forward) Info() Info {
return f.info
}
func (f *Forward) ParentID() int {
return 0
}
func (f *Forward) Type() string {
return f.name
}
func (f *Forward) String() string {
return f.name
}
func (f *Forward) Dump() string {
return fmt.Sprintf("%s %s %s",
isRootIDFmtStr(f.info.IsRoot(), f.id),
f.info.Kind(),
f.name,
)
}
func (f *Forward) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Info Info `json:"info,omitempty"`
}{
ID: f.id,
Name: f.name,
Info: f.info,
})
}
type Pointer struct {
id int
name string
info Info
reference uint
lookupFn func(int) Type
}
func (p *Pointer) ID() int {
return p.id
}
func (p *Pointer) Name() string {
return p.name
}
func (p *Pointer) Info() Info {
return p.info
}
func (p *Pointer) Reference() string {
if t := p.lookupFn(int(p.reference)); t != nil {
return t.Type()
}
return "<reference type not found>"
}
func (p *Pointer) ParentID() int {
return int(p.reference)
}
func (p *Pointer) Type() string {
return strings.TrimSuffix(p.String(), ";")
}
func (p *Pointer) String() string {
return fmt.Sprintf("%s *;", p.Reference())
}
func (p *Pointer) Dump() string {
return fmt.Sprintf("%s %s %s refers to %d",
isRootIDFmtStr(p.info.IsRoot(), p.id),
p.info.Kind(),
p.name,
p.reference,
)
}
func (p *Pointer) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Info Info `json:"info,omitempty"`
ReferenceID uint `json:"reference_id,omitempty"`
Reference string `json:"reference,omitempty"`
}{
ID: p.id,
Name: p.name,
Info: p.info,
ReferenceID: uint(p.reference),
Reference: p.Reference(),
})
}
type Typedef struct {
id int
name string
info Info
reference uint
lookupFn func(int) Type
}
func (p *Typedef) ID() int {
return p.id
}
func (p *Typedef) Name() string {
return p.name
}
func (p *Typedef) Info() Info {
return p.info
}
func (p *Typedef) Reference() string {
if t := p.lookupFn(int(p.reference)); t != nil {
return t.Type()
}
return "<reference type not found>"
}
func (p *Typedef) ParentID() int {
return int(p.reference)
}
func (p *Typedef) Type() string {
return p.Name()
}
func (p *Typedef) String() string {
return fmt.Sprintf("typedef %s %s", p.name, p.Reference())
}
func (p *Typedef) Dump() string {
return fmt.Sprintf("%s %s %s refers to %d",
isRootIDFmtStr(p.info.IsRoot(), p.id),
p.info.Kind(),
p.name,
p.reference,
)
}
func (p *Typedef) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Info Info `json:"info,omitempty"`
ReferenceID uint `json:"reference_id,omitempty"`
Reference string `json:"reference,omitempty"`
}{
ID: p.id,
Name: p.name,
Info: p.info,
ReferenceID: uint(p.reference),
Reference: p.Reference(),
})
}
type Volatile struct {
id int
name string
info Info
reference uint
lookupFn func(int) Type
}
func (p *Volatile) ID() int {
return p.id
}
func (p *Volatile) Name() string {
return p.name
}
func (p *Volatile) Info() Info {
return p.info
}
func (p *Volatile) Reference() string {
if t := p.lookupFn(int(p.reference)); t != nil {
return t.Type()
}
return "<reference type not found>"
}
func (p *Volatile) ParentID() int {
return int(p.reference)
}
func (p *Volatile) Type() string {
return fmt.Sprintf("volatile %s", p.Reference())
}
func (p *Volatile) String() string {
return fmt.Sprintf("volatile %s", p.Reference())
}
func (p *Volatile) Dump() string {
return fmt.Sprintf("%s %s %s refers to %d",
isRootIDFmtStr(p.info.IsRoot(), p.id),
p.info.Kind(),
p.name,
p.reference,
)
}
func (p *Volatile) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Info Info `json:"info,omitempty"`
ReferenceID uint `json:"reference_id,omitempty"`
Reference string `json:"reference,omitempty"`
}{
ID: p.id,
Name: p.name,
Info: p.info,
ReferenceID: uint(p.reference),
Reference: p.Reference(),
})
}
type Const struct {
id int
name string
info Info
reference uint
lookupFn func(int) Type
}
func (p *Const) ID() int {
return p.id
}
func (p *Const) Name() string {
return p.name
}
func (p *Const) Info() Info {
return p.info
}
func (p *Const) Reference() string {
if t := p.lookupFn(int(p.reference)); t != nil {
return t.Type()
}
return "<reference type not found>"
}
func (p *Const) ParentID() int {
return int(p.reference)
}
func (p *Const) Type() string {
return fmt.Sprintf("const %s", p.Reference())
}
func (p *Const) String() string {
return fmt.Sprintf("const %s", p.Reference())
}
func (p *Const) Dump() string {
return fmt.Sprintf("%s %s %s refers to %d",
isRootIDFmtStr(p.info.IsRoot(), p.id),
p.info.Kind(),
p.name,
p.reference,
)
}
func (p *Const) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Info Info `json:"info,omitempty"`
ReferenceID uint `json:"reference_id,omitempty"`
Reference string `json:"reference,omitempty"`
}{
ID: p.id,
Name: p.name,
Info: p.info,
ReferenceID: uint(p.reference),
Reference: p.Reference(),
})
}
type Restrict struct {
id int
name string
info Info
reference uint
lookupFn func(int) Type
}
func (p *Restrict) ID() int {
return p.id
}
func (p *Restrict) Name() string {
return p.name
}
func (p *Restrict) Info() Info {
return p.info
}
func (p *Restrict) Reference() string {
if t := p.lookupFn(int(p.reference)); t != nil {
return t.Type()
}
return "<reference type not found>"
}
func (p *Restrict) ParentID() int {
return int(p.reference)
}
func (p *Restrict) Type() string {
return fmt.Sprintf("restrict %s", p.Reference())
}
func (p *Restrict) String() string {
return fmt.Sprintf("restrict %s", p.Reference())
}
func (p *Restrict) Dump() string {
return fmt.Sprintf("%s %s %s refers to %d",
isRootIDFmtStr(p.info.IsRoot(), p.id),
p.info.Kind(),
p.name,
p.reference,
)
}
func (p *Restrict) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Info Info `json:"info,omitempty"`
ReferenceID uint `json:"reference_id,omitempty"`
Reference string `json:"reference,omitempty"`
}{
ID: p.id,
Name: p.name,
Info: p.info,
ReferenceID: uint(p.reference),
Reference: p.Reference(),
})
}
type PtrAuth struct {
id int
name string
info Info
data ptrAuthData
reference uint
lookupFn func(int) Type
}
func (p *PtrAuth) ID() int {
return p.id
}
func (p *PtrAuth) Name() string {
return p.name
}
func (p *PtrAuth) Info() Info {
return p.info
}
func (p *PtrAuth) Reference() string {
if t := p.lookupFn(int(p.reference)); t != nil {
return t.Type()
}
return "<reference type not found>"
}
func (p *PtrAuth) ParentID() int {
return int(p.reference)
}
func (p *PtrAuth) Type() string { return p.String() }
func (p *PtrAuth) String() string {
return fmt.Sprintf(
"%s __ptrauth(%s, %t, %04x)",
p.Reference(),
p.data.Key(),
p.data.Discriminated(),
p.data.Discriminator(),
)
}
func (p *PtrAuth) Dump() string {
return fmt.Sprintf("%s %s %s refers to %d (key=%s, addr_div=%t, div=%04x)",
isRootIDFmtStr(p.info.IsRoot(), p.id),
p.info.Kind(),
p.name,
p.reference,
p.data.Key(),
p.data.Discriminated(),
p.data.Discriminator(),
)
}
func (p *PtrAuth) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Info Info `json:"info,omitempty"`
Data ptrAuthData `json:"data,omitempty"`
ReferenceID uint `json:"reference_id,omitempty"`
Reference string `json:"reference,omitempty"`
}{
ID: p.id,
Name: p.name,
Info: p.info,
Data: p.data,
ReferenceID: uint(p.reference),
Reference: p.Reference(),
})
}
type global struct {
Address uint64 `json:"address,omitempty"`
Name string `json:"name,omitempty"`
Reference int `json:"reference,omitempty"`
Type Type `json:"type,omitempty"`
}
func (g global) String() string {
if g.Type != nil {
return fmt.Sprintf("%#x: %s %s", g.Address, g.Type.Type(), g.Name)
}
if g.Reference == 0 {
return fmt.Sprintf("%#x: <unknown> %s", g.Address, g.Name)
}
return fmt.Sprintf("%#x: %d %s", g.Address, g.Reference, g.Name)
}
type function struct {
Address uint64 `json:"address,omitempty"`
Name string `json:"name,omitempty"`
Return Type `json:"return,omitempty"`
Arguments []Type `json:"arguments,omitempty"`
}
func (f function) String() string {
var args []string
for _, arg := range f.Arguments {
args = append(args, arg.Type())
}
return fmt.Sprintf("%#x: %s %s(%s);", f.Address, f.Return.Type(), f.Name, strings.Join(args, ", "))
}
func isRootIDFmtStr(isroot bool, id int) string {
if isroot {
return fmt.Sprintf("<%d>", id)
}
return fmt.Sprintf("[%d]", id)
}
func (h header) String() string {
return fmt.Sprintf(
"Magic = %#x\n"+
"Version = %d\n"+
"Flags = %#x\n"+
"Parent Label = %s\n"+
"Parent Name = %s\n"+
"Label Offset = %d\n"+
"Obj Offset = %d\n"+
"Func Offset = %#x\n"+
"Type Offset = %#x\n"+
"Str Offset = %#x\n"+
"Str Len = %#x\n",
h.Preamble.Magic,
h.Preamble.Version,
h.Preamble.Flags,
h.ParentLabel,
h.ParentName,
h.LabelOffset,
h.ObjOffset,
h.FuncOffset,
h.TypeOffset,
h.StrOffset,
h.StrLen,
)
}