Skip to content

Commit 72ec930

Browse files
committed
Fix cgo for GCC 4.4
Firstly, with -Werror, GCC switched to printing warnings starting with "error:". Widening the string matches solves this as the messages are otherwise unchanged. Secondly, GCC 4.4 outputs DWARF sections with with NUL bytes in all the offsets and requires the relocation section for .debug_info to be processed in order to result in valid DWARF data. Thus we add minimal handling for relocation sections, which is sufficient for our needs. BUG=1 Fixes #1. R=rsc, iant CC=go-dev http://go/go-review/1017003
1 parent 6358cac commit 72ec930

7 files changed

+236
-6
lines changed

src/cmd/cgo/gcc.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ func (p *Prog) loadDebugInfo() {
7878
switch {
7979
default:
8080
continue;
81-
case strings.Index(line, "warning: useless type name in empty declaration") >= 0:
81+
case strings.Index(line, ": useless type name in empty declaration") >= 0:
8282
what = "type";
83-
case strings.Index(line, "warning: statement with no effect") >= 0:
83+
case strings.Index(line, ": statement with no effect") >= 0:
8484
what = "value";
8585
case strings.Index(line, "undeclared") >= 0:
8686
what = "error";
@@ -114,7 +114,7 @@ func (p *Prog) loadDebugInfo() {
114114
fatal("gcc failed:\n%s\non input:\n%s", stderr, b.Bytes());
115115
}
116116

117-
// Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
117+
// Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
118118
types := make([]dwarf.Type, len(names));
119119
r := d.Reader();
120120
for {
@@ -198,10 +198,10 @@ func (p *Prog) gccDebug(stdin []byte) (*dwarf.Data, string) {
198198
machine,
199199
"-Wall", // many warnings
200200
"-Werror", // warnings are errors
201-
"-o"+tmp, // write object to tmp
202-
"-gdwarf-2", // generate DWARF v2 debugging symbols
201+
"-o"+tmp, // write object to tmp
202+
"-gdwarf-2", // generate DWARF v2 debugging symbols
203203
"-c", // do not link
204-
"-xc", // input language is C
204+
"-xc", // input language is C
205205
"-", // read input from standard input
206206
};
207207
_, stderr, ok := run(stdin, concat(base, p.GccOptions));

src/pkg/debug/elf/file.go

+130
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package elf
77

88
import (
9+
"bytes";
910
"debug/dwarf";
1011
"encoding/binary";
1112
"fmt";
@@ -109,6 +110,13 @@ func (p *Prog) Open() io.ReadSeeker {
109110
return io.NewSectionReader(p.sr, 0, 1<<63 - 1);
110111
}
111112

113+
// A Symbol represents an entry in an ELF symbol table section.
114+
type Symbol struct {
115+
Name uint32;
116+
Info, Other byte;
117+
Section uint32;
118+
Value, Size uint64;
119+
}
112120

113121
/*
114122
* ELF reader
@@ -305,6 +313,60 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
305313
return f, nil;
306314
}
307315

316+
func (f *File) getSymbols() ([]Symbol, os.Error) {
317+
switch f.Class {
318+
case ELFCLASS64:
319+
return f.getSymbols64();
320+
}
321+
322+
return nil, os.ErrorString("not implemented");
323+
}
324+
325+
// GetSymbols returns a slice of Symbols from parsing the symbol table.
326+
func (f *File) getSymbols64() ([]Symbol, os.Error) {
327+
var symtabSection *Section;
328+
for _, section := range f.Sections {
329+
if section.Type == SHT_SYMTAB {
330+
symtabSection = section;
331+
break;
332+
}
333+
}
334+
335+
if symtabSection == nil {
336+
return nil, os.ErrorString("no symbol section");
337+
}
338+
339+
data, err := symtabSection.Data();
340+
if err != nil {
341+
return nil, os.ErrorString("cannot load symbol section");
342+
}
343+
symtab := bytes.NewBuffer(data);
344+
if symtab.Len() % Sym64Size != 0 {
345+
return nil, os.ErrorString("length of symbol section is not a multiple of Sym64Size");
346+
}
347+
348+
// The first entry is all zeros.
349+
var skip [Sym64Size]byte;
350+
symtab.Read(skip[0:len(skip)]);
351+
352+
symbols := make([]Symbol, symtab.Len() / Sym64Size);
353+
354+
i := 0;
355+
var sym Sym64;
356+
for symtab.Len() > 0 {
357+
binary.Read(symtab, f.ByteOrder, &sym);
358+
symbols[i].Name = sym.Name;
359+
symbols[i].Info = sym.Info;
360+
symbols[i].Other = sym.Other;
361+
symbols[i].Section = uint32(sym.Shndx);
362+
symbols[i].Value = sym.Value;
363+
symbols[i].Size = sym.Size;
364+
i++;
365+
}
366+
367+
return symbols, nil;
368+
}
369+
308370
// getString extracts a string from an ELF string table.
309371
func getString(section []byte, start int) (string, bool) {
310372
if start < 0 || start >= len(section) {
@@ -330,6 +392,60 @@ func (f *File) Section(name string) *Section {
330392
return nil;
331393
}
332394

395+
// applyRelocations applies relocations to dst. rels is a relocations section
396+
// in RELA format.
397+
func (f *File) applyRelocations(dst []byte, rels []byte) os.Error {
398+
if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 {
399+
return f.applyRelocationsAMD64(dst, rels);
400+
}
401+
402+
return os.ErrorString("not implemented");
403+
}
404+
405+
func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) os.Error {
406+
if len(rels) % Sym64Size != 0 {
407+
return os.ErrorString("length of relocation section is not a multiple of Sym64Size");
408+
}
409+
410+
symbols, err := f.getSymbols();
411+
if err != nil {
412+
return err;
413+
}
414+
415+
b := bytes.NewBuffer(rels);
416+
var rela Rela64;
417+
418+
for b.Len() > 0 {
419+
binary.Read(b, f.ByteOrder, &rela);
420+
symNo := rela.Info >> 32;
421+
t := R_X86_64(rela.Info & 0xffff);
422+
423+
if symNo >= uint64(len(symbols)) {
424+
continue;
425+
}
426+
sym := &symbols[symNo];
427+
if SymType(sym.Info & 0xf) != STT_SECTION {
428+
// We don't handle non-section relocations for now.
429+
continue;
430+
}
431+
432+
switch t {
433+
case R_X86_64_64:
434+
if rela.Off + 8 >= uint64(len(dst)) || rela.Addend < 0 {
435+
continue;
436+
}
437+
f.ByteOrder.PutUint64(dst[rela.Off : rela.Off + 8], uint64(rela.Addend));
438+
case R_X86_64_32:
439+
if rela.Off + 4 >= uint64(len(dst)) || rela.Addend < 0 {
440+
continue;
441+
}
442+
f.ByteOrder.PutUint32(dst[rela.Off : rela.Off + 4], uint32(rela.Addend));
443+
}
444+
}
445+
446+
return nil;
447+
}
448+
333449
func (f *File) DWARF() (*dwarf.Data, os.Error) {
334450
// There are many other DWARF sections, but these
335451
// are the required ones, and the debug/dwarf package
@@ -349,6 +465,20 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) {
349465
dat[i] = b;
350466
}
351467

468+
// If there's a relocation table for .debug_info, we have to process it
469+
// now otherwise the data in .debug_info is invalid for x86-64 objects.
470+
rela := f.Section(".rela.debug_info");
471+
if rela != nil && rela.Type == SHT_RELA && f.Machine == EM_X86_64 {
472+
data, err := rela.Data();
473+
if err != nil {
474+
return nil, err;
475+
}
476+
err = f.applyRelocations(dat[1], data);
477+
if err != nil {
478+
return nil, err;
479+
}
480+
}
481+
352482
abbrev, info, str := dat[0], dat[1], dat[2];
353483
return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str);
354484
}

src/pkg/debug/elf/file_test.go

+51
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package elf
66

77
import (
8+
"debug/dwarf";
89
"encoding/binary";
910
"reflect";
1011
"testing";
@@ -127,3 +128,53 @@ func TestOpen(t *testing.T) {
127128
}
128129
}
129130
}
131+
132+
type relocationTest struct {
133+
file string;
134+
firstEntry *dwarf.Entry;
135+
}
136+
137+
var relocationTests = []relocationTest{
138+
relocationTest{
139+
"testdata/go-relocation-test-gcc441-x86-64.o",
140+
&dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(1)}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test.c"}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp"}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0)}}},
141+
},
142+
relocationTest{
143+
"testdata/go-relocation-test-gcc441-x86.o",
144+
&dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(1)}, dwarf.Field{Attr: dwarf.AttrName, Val: "t.c"}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp"}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: uint64(0x5)}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0)}}},
145+
},
146+
relocationTest{
147+
"testdata/go-relocation-test-gcc424-x86-64.o",
148+
&dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(1)}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp"}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0)}}},
149+
},
150+
}
151+
152+
func TestDWARFRelocations(t *testing.T) {
153+
for i, test := range relocationTests {
154+
f, err := Open(test.file);
155+
if err != nil {
156+
t.Error(err);
157+
continue;
158+
}
159+
dwarf, err := f.DWARF();
160+
if err != nil {
161+
t.Error(err);
162+
continue;
163+
}
164+
reader := dwarf.Reader();
165+
// Checking only the first entry is sufficient since it has
166+
// many different strings. If the relocation had failed, all
167+
// the string offsets would be zero and all the strings would
168+
// end up being the same.
169+
firstEntry, err := reader.Next();
170+
if err != nil {
171+
t.Error(err);
172+
continue;
173+
}
174+
175+
if !reflect.DeepEqual(test.firstEntry, firstEntry) {
176+
t.Errorf("#%d: mismatch: got:%#v want:%#v", i, firstEntry, test.firstEntry);
177+
continue;
178+
}
179+
}
180+
}
Binary file not shown.
Binary file not shown.
Binary file not shown.

src/pkg/encoding/binary/binary.go

+49
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ type ByteOrder interface {
1919
Uint16(b []byte) uint16;
2020
Uint32(b []byte) uint32;
2121
Uint64(b []byte) uint64;
22+
PutUint16([]byte, uint16);
23+
PutUint32([]byte, uint32);
24+
PutUint64([]byte, uint64);
2225
String() string;
2326
}
2427

@@ -35,15 +38,38 @@ func (littleEndian) Uint16(b []byte) uint16 {
3538
return uint16(b[0]) | uint16(b[1])<<8;
3639
}
3740

41+
func (littleEndian) PutUint16(b []byte, v uint16) {
42+
b[0] = byte(v);
43+
b[1] = byte(v>>8);
44+
}
45+
3846
func (littleEndian) Uint32(b []byte) uint32 {
3947
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24;
4048
}
4149

50+
func (littleEndian) PutUint32(b []byte, v uint32) {
51+
b[0] = byte(v);
52+
b[1] = byte(v>>8);
53+
b[2] = byte(v>>16);
54+
b[3] = byte(v>>24);
55+
}
56+
4257
func (littleEndian) Uint64(b []byte) uint64 {
4358
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
4459
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56;
4560
}
4661

62+
func (littleEndian) PutUint64(b []byte, v uint64) {
63+
b[0] = byte(v);
64+
b[1] = byte(v>>8);
65+
b[2] = byte(v>>16);
66+
b[3] = byte(v>>24);
67+
b[4] = byte(v>>32);
68+
b[5] = byte(v>>40);
69+
b[6] = byte(v>>48);
70+
b[7] = byte(v>>56);
71+
}
72+
4773
func (littleEndian) String() string {
4874
return "LittleEndian";
4975
}
@@ -58,15 +84,38 @@ func (bigEndian) Uint16(b []byte) uint16 {
5884
return uint16(b[1]) | uint16(b[0])<<8;
5985
}
6086

87+
func (bigEndian) PutUint16(b []byte, v uint16) {
88+
b[0] = byte(v>>8);
89+
b[1] = byte(v);
90+
}
91+
6192
func (bigEndian) Uint32(b []byte) uint32 {
6293
return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24;
6394
}
6495

96+
func (bigEndian) PutUint32(b []byte, v uint32) {
97+
b[0] = byte(v>>24);
98+
b[1] = byte(v>>16);
99+
b[2] = byte(v>>8);
100+
b[3] = byte(v);
101+
}
102+
65103
func (bigEndian) Uint64(b []byte) uint64 {
66104
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
67105
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56;
68106
}
69107

108+
func (bigEndian) PutUint64(b []byte, v uint64) {
109+
b[0] = byte(v>>56);
110+
b[1] = byte(v>>48);
111+
b[2] = byte(v>>40);
112+
b[3] = byte(v>>32);
113+
b[4] = byte(v>>24);
114+
b[5] = byte(v>>16);
115+
b[6] = byte(v>>8);
116+
b[7] = byte(v);
117+
}
118+
70119
func (bigEndian) String() string {
71120
return "BigEndian";
72121
}

0 commit comments

Comments
 (0)