mirror of
https://github.com/golang/go
synced 2024-11-22 04:44:39 -07:00
debug/pe, cgo: add windows support
R=rsc, mattn CC=golang-dev https://golang.org/cl/1976045
This commit is contained in:
parent
e198a5086a
commit
035696c59a
@ -141,6 +141,7 @@ _CGO_CFLAGS_amd64=-m64
|
||||
_CGO_LDFLAGS_freebsd=-shared -lpthread -lm
|
||||
_CGO_LDFLAGS_linux=-shared -lpthread -lm
|
||||
_CGO_LDFLAGS_darwin=-dynamiclib -Wl,-undefined,dynamic_lookup
|
||||
_CGO_LDFLAGS_windows=-shared -lm -mthreads
|
||||
|
||||
# Compile x.cgo4.c with gcc to make package_x.so.
|
||||
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"debug/dwarf"
|
||||
"debug/elf"
|
||||
"debug/macho"
|
||||
"debug/pe"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
@ -504,7 +505,9 @@ func (p *Package) gccDebug(stdin []byte) *dwarf.Data {
|
||||
var err os.Error
|
||||
if f, err = elf.Open(gccTmp); err != nil {
|
||||
if f, err = macho.Open(gccTmp); err != nil {
|
||||
fatal("cannot parse gcc output %s as ELF or Mach-O object", gccTmp)
|
||||
if f, err = pe.Open(gccTmp); err != nil {
|
||||
fatal("cannot parse gcc output %s as ELF or Mach-O or PE object", gccTmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,7 @@ DIRS=\
|
||||
debug/macho\
|
||||
debug/elf\
|
||||
debug/gosym\
|
||||
debug/pe\
|
||||
debug/proc\
|
||||
ebnf\
|
||||
encoding/ascii85\
|
||||
|
12
src/pkg/debug/pe/Makefile
Normal file
12
src/pkg/debug/pe/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
# 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.
|
||||
|
||||
include ../../../Make.inc
|
||||
|
||||
TARG=debug/pe
|
||||
GOFILES=\
|
||||
pe.go\
|
||||
file.go\
|
||||
|
||||
include ../../../Make.pkg
|
231
src/pkg/debug/pe/file.go
Normal file
231
src/pkg/debug/pe/file.go
Normal file
@ -0,0 +1,231 @@
|
||||
// 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 pe implements access to PE (Microsoft Windows Portable Executable) files.
|
||||
package pe
|
||||
|
||||
import (
|
||||
"debug/dwarf"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// A File represents an open PE file.
|
||||
type File struct {
|
||||
FileHeader
|
||||
Sections []*Section
|
||||
|
||||
closer io.Closer
|
||||
}
|
||||
|
||||
type SectionHeader struct {
|
||||
Name string
|
||||
VirtualSize uint32
|
||||
VirtualAddress uint32
|
||||
Size uint32
|
||||
Offset uint32
|
||||
PointerToRelocations uint32
|
||||
PointerToLineNumbers uint32
|
||||
NumberOfRelocations uint16
|
||||
NumberOfLineNumbers uint16
|
||||
Characteristics uint32
|
||||
}
|
||||
|
||||
|
||||
type Section struct {
|
||||
SectionHeader
|
||||
|
||||
// Embed ReaderAt for ReadAt method.
|
||||
// Do not embed SectionReader directly
|
||||
// to avoid having Read and Seek.
|
||||
// If a client wants Read and Seek it must use
|
||||
// Open() to avoid fighting over the seek offset
|
||||
// with other clients.
|
||||
io.ReaderAt
|
||||
sr *io.SectionReader
|
||||
}
|
||||
|
||||
// Data reads and returns the contents of the PE section.
|
||||
func (s *Section) Data() ([]byte, os.Error) {
|
||||
dat := make([]byte, s.sr.Size())
|
||||
n, err := s.sr.ReadAt(dat, 0)
|
||||
return dat[0:n], err
|
||||
}
|
||||
|
||||
// Open returns a new ReadSeeker reading the PE section.
|
||||
func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
|
||||
|
||||
|
||||
type FormatError struct {
|
||||
off int64
|
||||
msg string
|
||||
val interface{}
|
||||
}
|
||||
|
||||
func (e *FormatError) String() string {
|
||||
msg := e.msg
|
||||
if e.val != nil {
|
||||
msg += fmt.Sprintf(" '%v'", e.val)
|
||||
}
|
||||
msg += fmt.Sprintf(" in record at byte %#x", e.off)
|
||||
return msg
|
||||
}
|
||||
|
||||
// Open opens the named file using os.Open and prepares it for use as a PE binary.
|
||||
func Open(name string) (*File, os.Error) {
|
||||
f, err := os.Open(name, os.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ff, err := NewFile(f)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
ff.closer = f
|
||||
return ff, nil
|
||||
}
|
||||
|
||||
// Close closes the File.
|
||||
// If the File was created using NewFile directly instead of Open,
|
||||
// Close has no effect.
|
||||
func (f *File) Close() os.Error {
|
||||
var err os.Error
|
||||
if f.closer != nil {
|
||||
err = f.closer.Close()
|
||||
f.closer = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// NewFile creates a new File for acecssing a PE binary in an underlying reader.
|
||||
func NewFile(r io.ReaderAt) (*File, os.Error) {
|
||||
f := new(File)
|
||||
sr := io.NewSectionReader(r, 0, 1<<63-1)
|
||||
|
||||
var dosheader [96]byte
|
||||
if _, err := r.ReadAt(dosheader[0:], 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var base int64
|
||||
if dosheader[0] == 'M' && dosheader[1] == 'Z' {
|
||||
var sign [4]byte
|
||||
r.ReadAt(sign[0:], int64(dosheader[0x3c]))
|
||||
if !(sign[0] == 'P' && sign[1] == 'E' && sign[2] == 0 && sign[3] == 0) {
|
||||
return nil, os.NewError("Invalid PE File Format.")
|
||||
}
|
||||
base = int64(dosheader[0x3c]) + 4
|
||||
} else {
|
||||
base = int64(0)
|
||||
}
|
||||
sr.Seek(base, 0)
|
||||
if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if f.FileHeader.Machine != IMAGE_FILE_MACHINE_UNKNOWN && f.FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64 && f.FileHeader.Machine != IMAGE_FILE_MACHINE_I386 {
|
||||
return nil, os.NewError("Invalid PE File Format.")
|
||||
}
|
||||
// get symbol string table
|
||||
sr.Seek(int64(f.FileHeader.PointerToSymbolTable+18*f.FileHeader.NumberOfSymbols), 0)
|
||||
var l uint32
|
||||
if err := binary.Read(sr, binary.LittleEndian, &l); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ss := make([]byte, l)
|
||||
if _, err := r.ReadAt(ss, int64(f.FileHeader.PointerToSymbolTable+18*f.FileHeader.NumberOfSymbols)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sr.Seek(base, 0)
|
||||
binary.Read(sr, binary.LittleEndian, &f.FileHeader)
|
||||
sr.Seek(int64(f.FileHeader.SizeOfOptionalHeader), 1) //Skip OptionalHeader
|
||||
f.Sections = make([]*Section, f.FileHeader.NumberOfSections)
|
||||
for i := 0; i < int(f.FileHeader.NumberOfSections); i++ {
|
||||
sh := new(SectionHeader32)
|
||||
if err := binary.Read(sr, binary.LittleEndian, sh); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var name string
|
||||
if sh.Name[0] == '\x2F' {
|
||||
si, _ := strconv.Atoi(cstring(sh.Name[1:]))
|
||||
name, _ = getString(ss, si)
|
||||
} else {
|
||||
name = cstring(sh.Name[0:])
|
||||
}
|
||||
s := new(Section)
|
||||
s.SectionHeader = SectionHeader{
|
||||
Name: name,
|
||||
VirtualSize: uint32(sh.VirtualSize),
|
||||
VirtualAddress: uint32(sh.VirtualAddress),
|
||||
Size: uint32(sh.SizeOfRawData),
|
||||
Offset: uint32(sh.PointerToRawData),
|
||||
PointerToRelocations: uint32(sh.PointerToRelocations),
|
||||
PointerToLineNumbers: uint32(sh.PointerToLineNumbers),
|
||||
NumberOfRelocations: uint16(sh.NumberOfRelocations),
|
||||
NumberOfLineNumbers: uint16(sh.NumberOfLineNumbers),
|
||||
Characteristics: uint32(sh.Characteristics),
|
||||
}
|
||||
s.sr = io.NewSectionReader(r, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
|
||||
s.ReaderAt = s.sr
|
||||
f.Sections[i] = s
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func cstring(b []byte) string {
|
||||
var i int
|
||||
for i = 0; i < len(b) && b[i] != 0; i++ {
|
||||
}
|
||||
return string(b[0:i])
|
||||
}
|
||||
|
||||
// getString extracts a string from symbol string table.
|
||||
func getString(section []byte, start int) (string, bool) {
|
||||
if start < 0 || start >= len(section) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
for end := start; end < len(section); end++ {
|
||||
if section[end] == 0 {
|
||||
return string(section[start:end]), true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Section returns the first section with the given name, or nil if no such
|
||||
// section exists.
|
||||
func (f *File) Section(name string) *Section {
|
||||
for _, s := range f.Sections {
|
||||
if s.Name == name {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) DWARF() (*dwarf.Data, os.Error) {
|
||||
// There are many other DWARF sections, but these
|
||||
// are the required ones, and the debug/dwarf package
|
||||
// does not use the others, so don't bother loading them.
|
||||
var names = [...]string{"abbrev", "info", "str"}
|
||||
var dat [len(names)][]byte
|
||||
for i, name := range names {
|
||||
name = ".debug_" + name
|
||||
s := f.Section(name)
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
b, err := s.Data()
|
||||
if err != nil && uint32(len(b)) < s.Size {
|
||||
return nil, err
|
||||
}
|
||||
dat[i] = b
|
||||
}
|
||||
|
||||
abbrev, info, str := dat[0], dat[1], dat[2]
|
||||
return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
|
||||
}
|
99
src/pkg/debug/pe/file_test.go
Normal file
99
src/pkg/debug/pe/file_test.go
Normal file
@ -0,0 +1,99 @@
|
||||
// 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 pe
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type fileTest struct {
|
||||
file string
|
||||
hdr FileHeader
|
||||
sections []*SectionHeader
|
||||
}
|
||||
|
||||
var fileTests = []fileTest{
|
||||
fileTest{
|
||||
"testdata/gcc-386-mingw-obj",
|
||||
FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104},
|
||||
[]*SectionHeader{
|
||||
&SectionHeader{".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020},
|
||||
&SectionHeader{".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264},
|
||||
&SectionHeader{".bss", 0, 0, 0, 0, 0, 0, 0, 0, 3224371328},
|
||||
&SectionHeader{".debug_abbrev", 0, 0, 137, 536, 0, 0, 0, 0, 0x42100000},
|
||||
&SectionHeader{".debug_info", 0, 0, 418, 673, 1470, 0, 7, 0, 1108344832},
|
||||
&SectionHeader{".debug_line", 0, 0, 128, 1091, 1540, 0, 1, 0, 1108344832},
|
||||
&SectionHeader{".rdata", 0, 0, 16, 1219, 0, 0, 0, 0, 1076887616},
|
||||
&SectionHeader{".debug_frame", 0, 0, 52, 1235, 1550, 0, 2, 0, 1110441984},
|
||||
&SectionHeader{".debug_loc", 0, 0, 56, 1287, 0, 0, 0, 0, 1108344832},
|
||||
&SectionHeader{".debug_pubnames", 0, 0, 27, 1343, 1570, 0, 1, 0, 1108344832},
|
||||
&SectionHeader{".debug_pubtypes", 0, 0, 38, 1370, 1580, 0, 1, 0, 1108344832},
|
||||
&SectionHeader{".debug_aranges", 0, 0, 32, 1408, 1590, 0, 2, 0, 1108344832},
|
||||
},
|
||||
},
|
||||
fileTest{
|
||||
"testdata/gcc-386-mingw-exec",
|
||||
FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107},
|
||||
[]*SectionHeader{
|
||||
&SectionHeader{Name: ".text", VirtualSize: 0xcd8, VirtualAddress: 0x1000, Size: 0xe00, Offset: 0x400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x60500060},
|
||||
&SectionHeader{Name: ".data", VirtualSize: 0x10, VirtualAddress: 0x2000, Size: 0x200, Offset: 0x1200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
|
||||
&SectionHeader{Name: ".rdata", VirtualSize: 0x120, VirtualAddress: 0x3000, Size: 0x200, Offset: 0x1400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x40300040},
|
||||
&SectionHeader{Name: ".bss", VirtualSize: 0xdc, VirtualAddress: 0x4000, Size: 0x0, Offset: 0x0, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0400080},
|
||||
&SectionHeader{Name: ".idata", VirtualSize: 0x3c8, VirtualAddress: 0x5000, Size: 0x400, Offset: 0x1600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
|
||||
&SectionHeader{Name: ".CRT", VirtualSize: 0x18, VirtualAddress: 0x6000, Size: 0x200, Offset: 0x1a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
|
||||
&SectionHeader{Name: ".tls", VirtualSize: 0x20, VirtualAddress: 0x7000, Size: 0x200, Offset: 0x1c00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
|
||||
&SectionHeader{Name: ".debug_aranges", VirtualSize: 0x20, VirtualAddress: 0x8000, Size: 0x200, Offset: 0x1e00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
|
||||
&SectionHeader{Name: ".debug_pubnames", VirtualSize: 0x51, VirtualAddress: 0x9000, Size: 0x200, Offset: 0x2000, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
|
||||
&SectionHeader{Name: ".debug_pubtypes", VirtualSize: 0x91, VirtualAddress: 0xa000, Size: 0x200, Offset: 0x2200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
|
||||
&SectionHeader{Name: ".debug_info", VirtualSize: 0xe22, VirtualAddress: 0xb000, Size: 0x1000, Offset: 0x2400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
|
||||
&SectionHeader{Name: ".debug_abbrev", VirtualSize: 0x157, VirtualAddress: 0xc000, Size: 0x200, Offset: 0x3400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
|
||||
&SectionHeader{Name: ".debug_line", VirtualSize: 0x144, VirtualAddress: 0xd000, Size: 0x200, Offset: 0x3600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
|
||||
&SectionHeader{Name: ".debug_frame", VirtualSize: 0x34, VirtualAddress: 0xe000, Size: 0x200, Offset: 0x3800, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42300000},
|
||||
&SectionHeader{Name: ".debug_loc", VirtualSize: 0x38, VirtualAddress: 0xf000, Size: 0x200, Offset: 0x3a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestOpen(t *testing.T) {
|
||||
for i := range fileTests {
|
||||
tt := &fileTests[i]
|
||||
|
||||
f, err := Open(tt.file)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
|
||||
t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
|
||||
continue
|
||||
}
|
||||
|
||||
for i, sh := range f.Sections {
|
||||
if i >= len(tt.sections) {
|
||||
break
|
||||
}
|
||||
have := &sh.SectionHeader
|
||||
want := tt.sections[i]
|
||||
if !reflect.DeepEqual(have, want) {
|
||||
t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
|
||||
}
|
||||
}
|
||||
tn := len(tt.sections)
|
||||
fn := len(f.Sections)
|
||||
if tn != fn {
|
||||
t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenFailure(t *testing.T) {
|
||||
filename := "file.go" // not a PE file
|
||||
_, err := Open(filename) // don't crash
|
||||
if err == nil {
|
||||
t.Errorf("open %s: succeeded unexpectedly", filename)
|
||||
}
|
||||
}
|
51
src/pkg/debug/pe/pe.go
Normal file
51
src/pkg/debug/pe/pe.go
Normal file
@ -0,0 +1,51 @@
|
||||
// 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 pe
|
||||
|
||||
type FileHeader struct {
|
||||
Machine uint16
|
||||
NumberOfSections uint16
|
||||
TimeDateStamp uint32
|
||||
PointerToSymbolTable uint32
|
||||
NumberOfSymbols uint32
|
||||
SizeOfOptionalHeader uint16
|
||||
Characteristics uint16
|
||||
}
|
||||
|
||||
type SectionHeader32 struct {
|
||||
Name [8]uint8
|
||||
VirtualSize uint32
|
||||
VirtualAddress uint32
|
||||
SizeOfRawData uint32
|
||||
PointerToRawData uint32
|
||||
PointerToRelocations uint32
|
||||
PointerToLineNumbers uint32
|
||||
NumberOfRelocations uint16
|
||||
NumberOfLineNumbers uint16
|
||||
Characteristics uint32
|
||||
}
|
||||
|
||||
const (
|
||||
IMAGE_FILE_MACHINE_UNKNOWN = 0x0
|
||||
IMAGE_FILE_MACHINE_AM33 = 0x1d3
|
||||
IMAGE_FILE_MACHINE_AMD64 = 0x8664
|
||||
IMAGE_FILE_MACHINE_ARM = 0x1c0
|
||||
IMAGE_FILE_MACHINE_EBC = 0xebc
|
||||
IMAGE_FILE_MACHINE_I386 = 0x14c
|
||||
IMAGE_FILE_MACHINE_IA64 = 0x200
|
||||
IMAGE_FILE_MACHINE_M32R = 0x9041
|
||||
IMAGE_FILE_MACHINE_MIPS16 = 0x266
|
||||
IMAGE_FILE_MACHINE_MIPSFPU = 0x366
|
||||
IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466
|
||||
IMAGE_FILE_MACHINE_POWERPC = 0x1f0
|
||||
IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1
|
||||
IMAGE_FILE_MACHINE_R4000 = 0x166
|
||||
IMAGE_FILE_MACHINE_SH3 = 0x1a2
|
||||
IMAGE_FILE_MACHINE_SH3DSP = 0x1a3
|
||||
IMAGE_FILE_MACHINE_SH4 = 0x1a6
|
||||
IMAGE_FILE_MACHINE_SH5 = 0x1a8
|
||||
IMAGE_FILE_MACHINE_THUMB = 0x1c2
|
||||
IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169
|
||||
)
|
BIN
src/pkg/debug/pe/testdata/gcc-386-mingw-exec
vendored
Normal file
BIN
src/pkg/debug/pe/testdata/gcc-386-mingw-exec
vendored
Normal file
Binary file not shown.
BIN
src/pkg/debug/pe/testdata/gcc-386-mingw-obj
vendored
Normal file
BIN
src/pkg/debug/pe/testdata/gcc-386-mingw-obj
vendored
Normal file
Binary file not shown.
8
src/pkg/debug/pe/testdata/hello.c
vendored
Normal file
8
src/pkg/debug/pe/testdata/hello.c
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
printf("hello, world\n");
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user