Skip to content

Commit 909af3e

Browse files
committed
Finish fleshing out COFF provider, get tests working for all
Also add tests for show() methods
1 parent 7195b18 commit 909af3e

23 files changed

+372
-966
lines changed

src/Abstract/Abstract.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Include our abstract base classes for everything
22
include("ObjectHandle.jl")
3+
include("Printing.jl")
34
include("Section.jl")
45
include("Segment.jl")
56
include("StrTab.jl")

src/Abstract/DynamicLink.jl

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ given below, with methods that subclasses must implement marked in emphasis:
2323
- *DynamicLinks()*
2424
2525
### Iteration
26-
- getindex()
26+
- *getindex()*
2727
- *endof()*
2828
- length()
2929
- start()
@@ -43,6 +43,7 @@ done(dls::DynamicLinks, idx) = idx > length(dls)
4343
next(dls::DynamicLinks, idx) = (dls[idx], idx+1)
4444
length(dls::DynamicLinks) = endof(dls)
4545
eltype(::Type{D}) where {D <: DynamicLinks} = DynamicLink
46+
@mustimplement getindex(dls::DynamicLinks, idx)
4647

4748
"""
4849
DynamicLink
@@ -82,7 +83,7 @@ marked in emphasis:
8283
### RPath operations
8384
- *rpaths()*
8485
- canonical_rpaths()
85-
- *find_library()*
86+
- find_library()
8687
"""
8788
abstract type RPath{H <: ObjectHandle} end
8889

@@ -107,6 +108,15 @@ Return the list of paths that will be searched for shared libraries.
107108
"""
108109
@mustimplement rpaths(rpath::RPath)
109110

111+
endof(rpath::RPath) = endof(rpaths(rpath))
112+
start(rpath::RPath) = 1
113+
done(rpath::RPath, idx) = idx > length(rpath)
114+
next(rpath::RPath, idx) = (rpath[idx], idx+1)
115+
length(rpath::RPath) = endof(rpath)
116+
eltype(::Type{D}) where {D <: RPath} = String
117+
getindex(rpath::RPath, idx) = rpaths(rpath)[idx]
118+
119+
110120
"""
111121
canonical_rpaths(rpath::RPath)
112122
@@ -145,3 +155,19 @@ function find_library(rpath::RPath, soname::String)
145155
end
146156
return soname
147157
end
158+
159+
160+
### Printing
161+
function show(io::IO, dl::DynamicLink{H}) where {H <: ObjectHandle}
162+
print(io, "$(format_string(H)) DynamicLink \"$(path(dl))\"")
163+
end
164+
165+
show(io::IO, dls::DynamicLinks{H}) where {H <: ObjectHandle} = show_collection(io, dls, H)
166+
show(io::IO, rp::RPath{H}) where {H <: ObjectHandle} = show_collection(io, rp, H)
167+
168+
# function show(io::IO, rpath::RPath{H}) where {H <: ObjectHandle}
169+
# print(io, "$(format_string(H)) RPaths")
170+
# for path in rpaths(rpath)
171+
# print(io, "\n $(path)")
172+
# end
173+
# end

src/Abstract/ObjectHandle.jl

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export ObjectHandle,
44
seek, seekstart, skip, start, iostream, position, read, readuntil, eof,
55
unpack,
66
endianness, is64bit, isrelocatable, isexecutable, islibrary,
7-
mangle_section_name, mangle_symbol_name, handle, header,
7+
mangle_section_name, mangle_symbol_name, handle, header, format_string,
88
section_header_offset, section_header_size, section_header_type,
99
segment_header_offset, segment_header_size, segment_header_type,
1010
symtab_entry_offset, symtab_entry_size, symtab_entry_type,
@@ -54,6 +54,7 @@ where `oh <: COFFHandle`).
5454
- *mangle_symbol_name()*
5555
- handle()
5656
- *header()*
57+
- *format_string()*
5758
5859
### Section properties
5960
- *section_header_offset()*
@@ -72,6 +73,7 @@ where `oh <: COFFHandle`).
7273
7374
### Misc
7475
- *path()*
76+
- show()
7577
- find_library()
7678
- find_libraries()
7779
"""
@@ -240,6 +242,15 @@ particular object file format.
240242
"""
241243
@mustimplement header(oh::ObjectHandle)
242244

245+
"""
246+
format_string(::Type{H}) where {H <: ObjectHandle}
247+
248+
Return the string name of the given `ObjectHandle`, examples are "ELF",
249+
"MachO", "COFF", etc...
250+
"""
251+
@mustimplement format_string(oh::Type)
252+
format_string(::H) where {H <: ObjectHandle} = format_string(H)
253+
243254
"""
244255
section_header_offset(oh::ObjectHandle)
245256
@@ -347,6 +358,10 @@ function path(io::IO)
347358
return ""
348359
end
349360

361+
function show(io::IO, oh::H) where {H <: ObjectHandle}
362+
print(io, "$(format_string(H)) Handle ($(is64bit(oh) ? "64" : "32")-bit)")
363+
end
364+
350365
"""
351366
find_library(oh::ObjectHandle, soname::String)
352367

src/Abstract/Printing.jl

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""
2+
show_collection(io, collection, ::Type{H<:ObjectHandle})
3+
4+
Given a collection-like object, (`Symbols`, `DynamicLinks`, ``)
5+
"""
6+
function show_collection(io::IO, stuff::ST, ::Type{H}) where {ST} where {H <: ObjectHandle}
7+
h_str = format_string(H)
8+
9+
# Get the type name, removing the `ELF`/`MachO`/`COFF` at the beginning
10+
type_name = if isa(ST, UnionAll)
11+
string(ST.body.name.name)
12+
else
13+
string(ST.name.name)
14+
end
15+
16+
if startswith(type_name, h_str)
17+
type_name = type_name[length(h_str)+1:end]
18+
end
19+
20+
# Start by outputting the container type
21+
print(io, h_str," ", type_name)
22+
23+
# Next, print either the entire thing, or a limited subsection of it
24+
limited = get(io, :limit, false)
25+
if limited && length(stuff) > 20
26+
for idx in 1:10
27+
print(io, "\n [$(idx)] ")
28+
showcompact(io, stuff[idx])
29+
end
30+
print(io, "\n \u2026")
31+
for idx in length(stuff)-10:length(stuff)
32+
print(io, "\n [$(idx)] ")
33+
showcompact(io, stuff[idx])
34+
end
35+
else
36+
for idx in 1:length(stuff)
37+
print(io, "\n [$(idx)] ")
38+
showcompact(io, stuff[idx])
39+
end
40+
end
41+
end

src/Abstract/Section.jl

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
export Sections,
33
getindex, endof, length, start, next, done, eltype,
44
find, findfirst,
5-
handle, header
5+
handle, header, format_string
66

77
# Export Section API
88
export Section,
@@ -118,7 +118,6 @@ Return the `ObjectHandle` that this `Sections` object belongs to
118118
@mustimplement handle(sections::Sections)
119119

120120

121-
122121
"""
123122
Section
124123
@@ -151,25 +150,10 @@ subclasses must implement marked in emphasis:
151150
"""
152151
abstract type Section{H<:ObjectHandle} end
153152

154-
deref(section::Section) = section
153+
# read() is how we construct a `Section`
155154
@mustimplement read(oh::ObjectHandle, ::Type{Section})
156155

157-
# """
158-
# position(section::Section)
159-
160-
# Return the position of a Section within a file
161-
# """
162-
# position(section::Section) = position(handle(x)) - section_offset(x)
163-
164-
165-
# """
166-
# seek(oh::ObjectHandle, section::Section)
167-
168-
# Seek the given `ObjectHandle` to the beginning of `section`
169-
# """
170-
# function seek(oh::H, section::Section{T}) where {H <: ObjectHandle, T <: H}
171-
# return seek(oh, section_offset(section))
172-
# end
156+
deref(section::Section) = section
173157

174158
"""
175159
contents(oh::ObjectHandle, section::Section)
@@ -345,4 +329,23 @@ function eof(section::SectionRef)
345329
# current section
346330
section_end = section_offset(section) + section_size(section)
347331
return position(handle(section)) >= section_end
348-
end
332+
end
333+
334+
335+
336+
# Common Printing
337+
function show(io::IO, s::Union{Section{H},SectionRef{H}}) where {H <: ObjectHandle}
338+
print(io, "$(format_string(H)) Section")
339+
340+
if !get(io, :compact, false)
341+
println(io)
342+
println(io, " Name: $(section_name(s))")
343+
println(io, " Size: 0x$(hex(section_size(s)))")
344+
println(io, " Offset: 0x$(hex(section_offset(s)))")
345+
print(io, " Address: 0x$(hex(section_address(s)))")
346+
else
347+
print(io, " \"$(section_name(s))\"")
348+
end
349+
end
350+
351+
show(io::IO, sects::Sections{H}) where {H <: ObjectHandle} = show_collection(io, sects, H)

src/Abstract/Segment.jl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,4 +190,9 @@ Return the index of the referred segment.
190190
@derefmethod segment_offset(seg::SegmentRef)
191191
@derefmethod segment_file_size(seg::SegmentRef)
192192
@derefmethod segment_memory_size(seg::SegmentRef)
193-
@derefmethod segment_address(seg::SegmentRef)
193+
@derefmethod segment_address(seg::SegmentRef)
194+
195+
196+
197+
## Printing
198+
show(io::IO, segs::Segments{H}) where {H <: ObjectHandle} = show_collection(io, segs, H)

src/Abstract/Symbol.jl

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,4 +223,24 @@ of the symbol.
223223
@derefmethod isundef(sym::SymbolRef)
224224
@derefmethod isglobal(sym::SymbolRef)
225225
@derefmethod islocal(sym::SymbolRef)
226-
@derefmethod isweak(sym::SymbolRef)
226+
@derefmethod isweak(sym::SymbolRef)
227+
228+
229+
230+
## Printing
231+
function show(io::IO, sym::Union{SymtabEntry{H},SymbolRef{H}}) where {H <: ObjectHandle}
232+
print(io, "$(format_string(H)) Symbol")
233+
234+
if !get(io, :compact, false)
235+
println(io)
236+
println(io, " Name: $(symbol_name(sym))")
237+
println(io, " Value: $(symbol_value(sym))")
238+
println(io, " Defined: $(isundef(sym) ? "No" : "Yes")")
239+
println(io, " Strong: $(isweak(sym) ? "No" : "Yes")")
240+
print(io, " Locality: $(isglobal(sym) ? "Global" : "Local")")
241+
else
242+
print(io, " \"$(symbol_name(sym))\"")
243+
end
244+
end
245+
246+
show(io::IO, syms::Symbols{H}) where {H <: ObjectHandle} = show_collection(io, syms, H)

src/COFF/COFFDynamicLink.jl

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,75 @@
1+
export COFFDynamicLinks, COFFDynamicLink, COFFRPath
2+
13
immutable COFFDynamicLink{H <: COFFHandle} <: DynamicLink{H}
24
path::String
3-
end
5+
end
6+
path(dl::COFFDynamicLink) = dl.path
7+
8+
9+
@io immutable COFFImageImportDescriptor
10+
Characteristics::UInt32
11+
TimeDateStamp::UInt32
12+
ForwarderChain::UInt32
13+
Name::UInt32
14+
FirstThunk::UInt32
15+
end
16+
17+
immutable COFFDynamicLinks{H <: COFFHandle} <: DynamicLinks{H}
18+
handle::H
19+
links::Vector
20+
end
21+
22+
function import_name(oh::COFFHandle, idata::COFFSectionRef, iid)
23+
seek(oh, iid.Name - section_address(idata) + section_offset(idata))
24+
return strip(readuntil(oh, '\0'), '\0')
25+
end
26+
27+
function COFFDynamicLinks(oh::H) where {H <: COFFHandle}
28+
# Find the import table section
29+
idata = findfirst(Sections(oh), ".idata")
30+
31+
# We'll load in all the ImageImportDescriptors we can
32+
iids = COFFImageImportDescriptor[]
33+
34+
# Read in ImageImportDescriptors until it's all NULL
35+
seek(oh, section_offset(idata))
36+
while true
37+
iid = unpack(oh, COFFImageImportDescriptor)
38+
if iid.Name == 0 && iid.FirstThunk == 0
39+
break
40+
else
41+
push!(iids, iid)
42+
end
43+
end
44+
45+
# Now, jump around and get all the strings
46+
links = [COFFDynamicLink{H}(import_name(oh, idata, iid)) for iid in iids]
47+
return COFFDynamicLinks(oh, links)
48+
end
49+
DynamicLinks(oh::COFFHandle) = COFFDynamicLinks(oh)
50+
51+
handle(dls::COFFDynamicLinks) = dls.handle
52+
endof(dls::COFFDynamicLinks) = endof(dls.links)
53+
getindex(dls::COFFDynamicLinks, idx) = getindex(dls.links, idx)
54+
55+
56+
"""
57+
COFFRPath
58+
59+
COFF RPath object; note that while COFF files do not have an RPath within them,
60+
they _do_ seach the same directory as the loading binary (e.g. the `\$ORIGIN`).
61+
We use `COFFRPath` to effect this, although strictly speaking there is no such
62+
thing as a "COFF RPath".
63+
"""
64+
immutable COFFRPath{H <: COFFHandle} <: RPath{H}
65+
handle::H
66+
end
67+
68+
RPath(oh::COFFHandle) = COFFRPath(oh)
69+
handle(crp::COFFRPath) = crp.handle
70+
rpaths(crp::COFFRPath) = String[]
71+
72+
# COFF files don't have an RPath, but they _do_ always search the $ORIGIN
73+
function canonical_rpaths(crp::COFFRPath)
74+
return [dirname(path(handle(crp)))]
75+
end

src/COFF/COFFHandle.jl

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,15 @@ isrelocatable(oh::COFFHandle) = isrelocatable(header(oh))
8181
isexecutable(oh::COFFHandle) = isexecutable(header(oh))
8282
islibrary(oh::COFFHandle) = islibrary(header(oh))
8383
mangle_section_name(oh::COFFHandle, name::AbstractString) = string(".", name)
84-
mangle_symbol_name(oh::COFFHandle, name::AbstractString) = name
85-
84+
function mangle_symbol_name(oh::COFFHandle, name::AbstractString)
85+
# sob
86+
if is64bit(oh)
87+
return name
88+
else
89+
return string("_", name)
90+
end
91+
end
92+
format_string(::Type{H}) where {H <: COFFHandle} = "COFF"
8693

8794
## Section information
8895
function section_header_offset(oh::COFFHandle)
@@ -101,4 +108,7 @@ symtab_entry_type(oh::H) where {H <: COFFHandle} = COFFSymtabEntry{H}
101108
function strtab_offset(oh::H) where {H <: COFFHandle}
102109
h = header(oh)
103110
return h.PointerToSymbolTable + h.NumberOfSymbols*symtab_entry_size(oh)
104-
end
111+
end
112+
113+
### Misc. stuff
114+
path(oh::COFFHandle) = oh.path

src/COFF/COFFSection.jl

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,12 @@ deref(s::COFFSectionRef) = s.section
6666
sections(s::COFFSectionRef) = s.sections
6767
handle(s::COFFSectionRef) = handle(sections(s))
6868
section_number(s::COFFSectionRef) = s.idx
69-
section_name(s::COFFSectionRef) = fixed_string_lookup(handle(s), deref(s).Name)
69+
function section_name(s::COFFSectionRef)
70+
name = unsafe_string(deref(s).Name)
71+
if !isempty(name) && name[1] == '/'
72+
# Wow, COFF files are weird.
73+
strtab = StrTab(handle(s))
74+
return strtab_lookup(strtab, parse(Int, name[2:end]))
75+
end
76+
return name
77+
end

0 commit comments

Comments
 (0)