// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build go1.7

package elf

import (
	"io"
	"path"
	"reflect"
	"testing"
)

// TODO: remove duplicate code
func TestSymbols(t *testing.T) {
	do := func(file string, ts []Symbol, getfunc func(*File) ([]Symbol, error)) {
		var f *File
		var err error
		if path.Ext(file) == ".gz" {
			var r io.ReaderAt
			if r, err = decompress(file); err == nil {
				f, err = NewFile(r)
			}
		} else {
			f, err = Open(file)
		}
		if err != nil {
			t.Errorf("TestSymbols: cannot open file %s: %v", file, err)
			return
		}
		defer f.Close()
		fs, err := getfunc(f)
		if err != nil && err != ErrNoSymbols {
			t.Error(err)
			return
		} else if err == ErrNoSymbols {
			fs = []Symbol{}
		}
		if !reflect.DeepEqual(ts, fs) {
			t.Errorf("%s: Symbols = %v, want %v", file, ts, fs)
		}
	}
	for file, ts := range symbolsGolden {
		do(file, ts, (*File).Symbols)
	}
	for file, ts := range dynamicSymbolsGolden {
		do(file, ts, (*File).DynamicSymbols)
	}
}

// golden symbol table data generated by testdata/getgoldsym.c

var symbolsGolden = map[string][]Symbol{
	"testdata/gcc-amd64-linux-exec": {
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x1,
			Value:   0x400200,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x2,
			Value:   0x40021C,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x3,
			Value:   0x400240,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x4,
			Value:   0x400268,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x5,
			Value:   0x400288,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x6,
			Value:   0x4002E8,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x7,
			Value:   0x400326,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x8,
			Value:   0x400330,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x9,
			Value:   0x400350,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0xA,
			Value:   0x400368,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0xB,
			Value:   0x400398,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0xC,
			Value:   0x4003B0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0xD,
			Value:   0x4003E0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0xE,
			Value:   0x400594,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0xF,
			Value:   0x4005A4,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x10,
			Value:   0x4005B8,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x11,
			Value:   0x4005E0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x12,
			Value:   0x600688,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x13,
			Value:   0x600698,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x14,
			Value:   0x6006A8,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x15,
			Value:   0x6006B0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x16,
			Value:   0x600850,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x17,
			Value:   0x600858,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x18,
			Value:   0x600880,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x19,
			Value:   0x600898,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x1A,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x1B,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x1C,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x1D,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x1E,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x1F,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x20,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x21,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "init.c",
			Info:    0x4,
			Other:   0x0,
			Section: 0xFFF1,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "initfini.c",
			Info:    0x4,
			Other:   0x0,
			Section: 0xFFF1,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "call_gmon_start",
			Info:    0x2,
			Other:   0x0,
			Section: 0xD,
			Value:   0x40040C,
			Size:    0x0,
		},
		Symbol{
			Name:    "crtstuff.c",
			Info:    0x4,
			Other:   0x0,
			Section: 0xFFF1,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "__CTOR_LIST__",
			Info:    0x1,
			Other:   0x0,
			Section: 0x12,
			Value:   0x600688,
			Size:    0x0,
		},
		Symbol{
			Name:    "__DTOR_LIST__",
			Info:    0x1,
			Other:   0x0,
			Section: 0x13,
			Value:   0x600698,
			Size:    0x0,
		},
		Symbol{
			Name:    "__JCR_LIST__",
			Info:    0x1,
			Other:   0x0,
			Section: 0x14,
			Value:   0x6006A8,
			Size:    0x0,
		},
		Symbol{
			Name:    "__do_global_dtors_aux",
			Info:    0x2,
			Other:   0x0,
			Section: 0xD,
			Value:   0x400430,
			Size:    0x0,
		},
		Symbol{
			Name:    "completed.6183",
			Info:    0x1,
			Other:   0x0,
			Section: 0x19,
			Value:   0x600898,
			Size:    0x1,
		},
		Symbol{
			Name:    "p.6181",
			Info:    0x1,
			Other:   0x0,
			Section: 0x18,
			Value:   0x600890,
			Size:    0x0,
		},
		Symbol{
			Name:    "frame_dummy",
			Info:    0x2,
			Other:   0x0,
			Section: 0xD,
			Value:   0x400470,
			Size:    0x0,
		},
		Symbol{
			Name:    "crtstuff.c",
			Info:    0x4,
			Other:   0x0,
			Section: 0xFFF1,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "__CTOR_END__",
			Info:    0x1,
			Other:   0x0,
			Section: 0x12,
			Value:   0x600690,
			Size:    0x0,
		},
		Symbol{
			Name:    "__DTOR_END__",
			Info:    0x1,
			Other:   0x0,
			Section: 0x13,
			Value:   0x6006A0,
			Size:    0x0,
		},
		Symbol{
			Name:    "__FRAME_END__",
			Info:    0x1,
			Other:   0x0,
			Section: 0x11,
			Value:   0x400680,
			Size:    0x0,
		},
		Symbol{
			Name:    "__JCR_END__",
			Info:    0x1,
			Other:   0x0,
			Section: 0x14,
			Value:   0x6006A8,
			Size:    0x0,
		},
		Symbol{
			Name:    "__do_global_ctors_aux",
			Info:    0x2,
			Other:   0x0,
			Section: 0xD,
			Value:   0x400560,
			Size:    0x0,
		},
		Symbol{
			Name:    "initfini.c",
			Info:    0x4,
			Other:   0x0,
			Section: 0xFFF1,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "hello.c",
			Info:    0x4,
			Other:   0x0,
			Section: 0xFFF1,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "_GLOBAL_OFFSET_TABLE_",
			Info:    0x1,
			Other:   0x2,
			Section: 0x17,
			Value:   0x600858,
			Size:    0x0,
		},
		Symbol{
			Name:    "__init_array_end",
			Info:    0x0,
			Other:   0x2,
			Section: 0x12,
			Value:   0x600684,
			Size:    0x0,
		},
		Symbol{
			Name:    "__init_array_start",
			Info:    0x0,
			Other:   0x2,
			Section: 0x12,
			Value:   0x600684,
			Size:    0x0,
		},
		Symbol{
			Name:    "_DYNAMIC",
			Info:    0x1,
			Other:   0x2,
			Section: 0x15,
			Value:   0x6006B0,
			Size:    0x0,
		},
		Symbol{
			Name:    "data_start",
			Info:    0x20,
			Other:   0x0,
			Section: 0x18,
			Value:   0x600880,
			Size:    0x0,
		},
		Symbol{
			Name:    "__libc_csu_fini",
			Info:    0x12,
			Other:   0x0,
			Section: 0xD,
			Value:   0x4004C0,
			Size:    0x2,
		},
		Symbol{
			Name:    "_start",
			Info:    0x12,
			Other:   0x0,
			Section: 0xD,
			Value:   0x4003E0,
			Size:    0x0,
		},
		Symbol{
			Name:    "__gmon_start__",
			Info:    0x20,
			Other:   0x0,
			Section: 0x0,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "_Jv_RegisterClasses",
			Info:    0x20,
			Other:   0x0,
			Section: 0x0,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "puts@@GLIBC_2.2.5",
			Info:    0x12,
			Other:   0x0,
			Section: 0x0,
			Value:   0x0,
			Size:    0x18C,
		},
		Symbol{
			Name:    "_fini",
			Info:    0x12,
			Other:   0x0,
			Section: 0xE,
			Value:   0x400594,
			Size:    0x0,
		},
		Symbol{
			Name:    "__libc_start_main@@GLIBC_2.2.5",
			Info:    0x12,
			Other:   0x0,
			Section: 0x0,
			Value:   0x0,
			Size:    0x1C2,
		},
		Symbol{
			Name:    "_IO_stdin_used",
			Info:    0x11,
			Other:   0x0,
			Section: 0xF,
			Value:   0x4005A4,
			Size:    0x4,
		},
		Symbol{
			Name:    "__data_start",
			Info:    0x10,
			Other:   0x0,
			Section: 0x18,
			Value:   0x600880,
			Size:    0x0,
		},
		Symbol{
			Name:    "__dso_handle",
			Info:    0x11,
			Other:   0x2,
			Section: 0x18,
			Value:   0x600888,
			Size:    0x0,
		},
		Symbol{
			Name:    "__libc_csu_init",
			Info:    0x12,
			Other:   0x0,
			Section: 0xD,
			Value:   0x4004D0,
			Size:    0x89,
		},
		Symbol{
			Name:    "__bss_start",
			Info:    0x10,
			Other:   0x0,
			Section: 0xFFF1,
			Value:   0x600898,
			Size:    0x0,
		},
		Symbol{
			Name:    "_end",
			Info:    0x10,
			Other:   0x0,
			Section: 0xFFF1,
			Value:   0x6008A0,
			Size:    0x0,
		},
		Symbol{
			Name:    "_edata",
			Info:    0x10,
			Other:   0x0,
			Section: 0xFFF1,
			Value:   0x600898,
			Size:    0x0,
		},
		Symbol{
			Name:    "main",
			Info:    0x12,
			Other:   0x0,
			Section: 0xD,
			Value:   0x400498,
			Size:    0x1B,
		},
		Symbol{
			Name:    "_init",
			Info:    0x12,
			Other:   0x0,
			Section: 0xB,
			Value:   0x400398,
			Size:    0x0,
		},
	},
	"testdata/go-relocation-test-clang-x86.obj": {
		Symbol{
			Name:    "go-relocation-test-clang.c",
			Info:    0x4,
			Other:   0x0,
			Section: 0xFFF1,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    ".Linfo_string0",
			Info:    0x0,
			Other:   0x0,
			Section: 0xC,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    ".Linfo_string1",
			Info:    0x0,
			Other:   0x0,
			Section: 0xC,
			Value:   0x2C,
			Size:    0x0,
		},
		Symbol{
			Name:    ".Linfo_string2",
			Info:    0x0,
			Other:   0x0,
			Section: 0xC,
			Value:   0x47,
			Size:    0x0,
		},
		Symbol{
			Name:    ".Linfo_string3",
			Info:    0x0,
			Other:   0x0,
			Section: 0xC,
			Value:   0x4C,
			Size:    0x0,
		},
		Symbol{
			Name:    ".Linfo_string4",
			Info:    0x0,
			Other:   0x0,
			Section: 0xC,
			Value:   0x4E,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x1,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x2,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x3,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x4,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x6,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x7,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x8,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0xA,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0xC,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0xD,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0xE,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0xF,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "",
			Info:    0x3,
			Other:   0x0,
			Section: 0x10,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "v",
			Info:    0x11,
			Other:   0x0,
			Section: 0xFFF2,
			Value:   0x4,
			Size:    0x4,
		},
	},
	"testdata/hello-world-core.gz": {},
}

var dynamicSymbolsGolden = map[string][]Symbol{
	"testdata/gcc-amd64-linux-exec": {
		Symbol{
			Name:    "__gmon_start__",
			Info:    0x20,
			Other:   0x0,
			Section: 0x0,
			Value:   0x0,
			Size:    0x0,
		},
		Symbol{
			Name:    "puts",
			Info:    0x12,
			Other:   0x0,
			Section: 0x0,
			Value:   0x0,
			Size:    0x18C,
		},
		Symbol{
			Name:    "__libc_start_main",
			Info:    0x12,
			Other:   0x0,
			Section: 0x0,
			Value:   0x0,
			Size:    0x1C2,
		},
	},
	"testdata/go-relocation-test-clang-x86.obj": {},
	"testdata/hello-world-core.gz":              {},
}
