mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
Support parsing of 64-bit ELF section tags off from the multiboot data
This commit is contained in:
parent
af9613e336
commit
a79be7c268
@ -6,6 +6,12 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
infoData uintptr
|
||||||
|
cmdLineKV map[string]string
|
||||||
|
elfSectionList []*ElfSection
|
||||||
|
)
|
||||||
|
|
||||||
type tagType uint32
|
type tagType uint32
|
||||||
|
|
||||||
// nolint
|
// nolint
|
||||||
@ -140,11 +146,6 @@ const (
|
|||||||
memUnknown
|
memUnknown
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
infoData uintptr
|
|
||||||
cmdLineKV map[string]string
|
|
||||||
)
|
|
||||||
|
|
||||||
// MemRegionVisitor defies a visitor function that gets invoked by VisitMemRegions
|
// MemRegionVisitor defies a visitor function that gets invoked by VisitMemRegions
|
||||||
// for each memory region provided by the boot loader. The visitor must return true
|
// for each memory region provided by the boot loader. The visitor must return true
|
||||||
// to continue or false to abort the scan.
|
// to continue or false to abort the scan.
|
||||||
@ -179,6 +180,115 @@ func (t MemoryEntryType) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type elfSections struct {
|
||||||
|
numSections uint16
|
||||||
|
sectionSize uint32
|
||||||
|
strtabSectionIndex uint32
|
||||||
|
sectionData [0]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
type elfSection32 struct {
|
||||||
|
nameIndex uint32
|
||||||
|
sectionType uint32
|
||||||
|
flags uint32
|
||||||
|
address uint32
|
||||||
|
offset uint32
|
||||||
|
size uint32
|
||||||
|
link uint32
|
||||||
|
info uint32
|
||||||
|
addrAlign uint32
|
||||||
|
entSize uint32
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
type elfSection64 struct {
|
||||||
|
nameIndex uint32
|
||||||
|
sectionType uint32
|
||||||
|
flags uint64
|
||||||
|
address uint64
|
||||||
|
offset uint64
|
||||||
|
size uint64
|
||||||
|
link uint32
|
||||||
|
info uint32
|
||||||
|
addrAlign uint64
|
||||||
|
entSize uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// ElfSectionFlag defines an OR-able flag associated with an ElfSection.
|
||||||
|
type ElfSectionFlag uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ElfSectionWritable marks the section as writable.
|
||||||
|
ElfSectionWritable ElfSectionFlag = 1 << iota
|
||||||
|
|
||||||
|
// ElfSectionAllocated means that the section is allocated in memory
|
||||||
|
// when the image is loaded (e.g .bss sections)
|
||||||
|
ElfSectionAllocated
|
||||||
|
|
||||||
|
// ElfSectionExecutable marks the section as executable.
|
||||||
|
ElfSectionExecutable
|
||||||
|
)
|
||||||
|
|
||||||
|
// ElfSection deefines the name, flags and virtual address of an ELF section
|
||||||
|
// which is part of the kernel image.
|
||||||
|
type ElfSection struct {
|
||||||
|
// The section name.
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// The list of flags associated with this section
|
||||||
|
Flags ElfSectionFlag
|
||||||
|
|
||||||
|
// The virtual address of this section.
|
||||||
|
Address uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetElfSections returns a slice of ElfSections for the loaded kernel image.
|
||||||
|
func GetElfSections() []*ElfSection {
|
||||||
|
if elfSectionList != nil {
|
||||||
|
return elfSectionList
|
||||||
|
}
|
||||||
|
|
||||||
|
curPtr, size := findTagByType(tagElfSymbols)
|
||||||
|
if size == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrElfSections := (*elfSections)(unsafe.Pointer(curPtr))
|
||||||
|
sectionData := *(*[]elfSection64)(unsafe.Pointer(&reflect.SliceHeader{
|
||||||
|
Len: int(ptrElfSections.numSections),
|
||||||
|
Cap: int(ptrElfSections.numSections),
|
||||||
|
Data: uintptr(unsafe.Pointer(&ptrElfSections.sectionData)),
|
||||||
|
}))
|
||||||
|
|
||||||
|
var (
|
||||||
|
strTable = *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
|
||||||
|
Len: int(sectionData[ptrElfSections.strtabSectionIndex].size),
|
||||||
|
Cap: int(sectionData[ptrElfSections.strtabSectionIndex].size),
|
||||||
|
Data: uintptr(sectionData[ptrElfSections.strtabSectionIndex].address),
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, secData := range sectionData {
|
||||||
|
if secData.size == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// String table entries are C-style NULL-terminated strings
|
||||||
|
end := secData.nameIndex
|
||||||
|
for ; strTable[end] != 0; end++ {
|
||||||
|
}
|
||||||
|
|
||||||
|
elfSectionList = append(elfSectionList, &ElfSection{
|
||||||
|
Name: string(strTable[secData.nameIndex:end]),
|
||||||
|
Flags: ElfSectionFlag(secData.flags),
|
||||||
|
Address: uintptr(secData.address),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return elfSectionList
|
||||||
|
}
|
||||||
|
|
||||||
// SetInfoPtr updates the internal multiboot information pointer to the given
|
// SetInfoPtr updates the internal multiboot information pointer to the given
|
||||||
// value. This function must be invoked before invoking any other function
|
// value. This function must be invoked before invoking any other function
|
||||||
// exported by this package.
|
// exported by this package.
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package multiboot
|
package multiboot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
@ -191,6 +193,62 @@ func TestGetBootCmdLine(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetElfSections(t *testing.T) {
|
||||||
|
SetInfoPtr(uintptr(unsafe.Pointer(&emptyInfoData[0])))
|
||||||
|
|
||||||
|
if GetElfSections() != nil {
|
||||||
|
t.Fatalf("expected GetElfSections() to return nil when no elf sections tag is present")
|
||||||
|
}
|
||||||
|
|
||||||
|
SetInfoPtr(uintptr(unsafe.Pointer(&multibootInfoTestData[0])))
|
||||||
|
|
||||||
|
// Patch the strtab address to point to out mock data
|
||||||
|
var buf bytes.Buffer
|
||||||
|
binary.Write(&buf, binary.LittleEndian, uint64(uintptr(unsafe.Pointer(&mockStrTable[0]))))
|
||||||
|
for i, b := range buf.Bytes() {
|
||||||
|
multibootInfoTestData[1660+i] = b
|
||||||
|
}
|
||||||
|
|
||||||
|
sections := GetElfSections()
|
||||||
|
|
||||||
|
specs := []struct {
|
||||||
|
secName string
|
||||||
|
expFlags ElfSectionFlag
|
||||||
|
}{
|
||||||
|
{".text", ElfSectionAllocated | ElfSectionExecutable},
|
||||||
|
{".bss", ElfSectionAllocated | ElfSectionWritable},
|
||||||
|
{".noptrbss", ElfSectionAllocated | ElfSectionWritable},
|
||||||
|
{".data", ElfSectionAllocated | ElfSectionWritable},
|
||||||
|
{".rodata", ElfSectionAllocated},
|
||||||
|
{".strtab", 0},
|
||||||
|
}
|
||||||
|
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
var found *ElfSection
|
||||||
|
for _, sec := range sections {
|
||||||
|
if sec.Name == spec.secName {
|
||||||
|
found = sec
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if found == nil {
|
||||||
|
t.Errorf("[spec %d] missing section %q", specIndex, spec.secName)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if found.Flags != spec.expFlags {
|
||||||
|
t.Errorf("[spec %d] expected section flags to be: 0x%x; got 0x%x", specIndex, spec.expFlags, found.Flags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second call should return the memoized data
|
||||||
|
sections[0].Name = "foo"
|
||||||
|
if sections2 := GetElfSections(); !reflect.DeepEqual(sections2, sections) {
|
||||||
|
t.Error("expected second call to GetElfSections() to return the memoized section list")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
emptyInfoData = []byte{
|
emptyInfoData = []byte{
|
||||||
0, 0, 0, 0, // size
|
0, 0, 0, 0, // size
|
||||||
@ -374,4 +432,23 @@ var (
|
|||||||
0x59, 0x42, 0x4f, 0x43, 0x48, 0x53, 0x20, 0x00, 0xdc, 0x18, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x00,
|
0x59, 0x42, 0x4f, 0x43, 0x48, 0x53, 0x20, 0x00, 0xdc, 0x18, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mockStrTable = []byte{
|
||||||
|
0x00, 0x2e, 0x73, 0x79, 0x6d, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, // ..symtab..strtab
|
||||||
|
0x00, 0x2e, 0x73, 0x68, 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x74, 0x65, 0x78, 0x74, // ..shstrtab..text
|
||||||
|
0x00, 0x2e, 0x72, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x00, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x6c, 0x69, // ..rodata..typeli
|
||||||
|
0x6e, 0x6b, 0x00, 0x2e, 0x69, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x6e, 0x6b, 0x00, 0x2e, 0x67, 0x6f, // nk..itablink..go
|
||||||
|
0x70, 0x63, 0x6c, 0x6e, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x00, 0x2e, 0x6e, // pclntab..data..n
|
||||||
|
0x6f, 0x70, 0x74, 0x72, 0x64, 0x61, 0x74, 0x61, 0x00, 0x2e, 0x62, 0x73, 0x73, 0x00, 0x2e, 0x6e, // optrdata..bss..n
|
||||||
|
0x6f, 0x70, 0x74, 0x72, 0x62, 0x73, 0x73, 0x00, 0x2e, 0x67, 0x6f, 0x72, 0x65, 0x64, 0x69, 0x72, // optrbss..goredir
|
||||||
|
0x65, 0x63, 0x74, 0x73, 0x74, 0x62, 0x6c, 0x00, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x2e, 0x67, 0x6f, // ectstbl..note.go
|
||||||
|
0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x69, 0x64, 0x00, 0x2e, 0x74, 0x62, 0x73, 0x73, 0x00, 0x2e, // .buildid..tbss..
|
||||||
|
0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x61, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x00, 0x2e, 0x64, // debug_aranges..d
|
||||||
|
0x65, 0x62, 0x75, 0x67, 0x5f, 0x70, 0x75, 0x62, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x00, 0x2e, 0x64, // ebug_pubnames..d
|
||||||
|
0x65, 0x62, 0x75, 0x67, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, // ebug_info..debug
|
||||||
|
0x5f, 0x61, 0x62, 0x62, 0x72, 0x65, 0x76, 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x6c, // _abbrev..debug_l
|
||||||
|
0x69, 0x6e, 0x65, 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, // ine..debug_frame
|
||||||
|
0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x6c, 0x6f, 0x63, 0x00, 0x2e, 0x64, 0x65, 0x62, // ..debug_loc..deb
|
||||||
|
0x75, 0x67, 0x5f, 0x70, 0x75, 0x62, 0x74, 0x79, 0x70, 0x65, 0x73, 0x00, // ug_pubtypes.
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user