1 //          Copyright Yazan Dabain 2014.
2 // Distributed under the Boost Software License, Version 1.0.
3 //    (See accompanying file LICENSE_1_0.txt or copy at
4 //          http://www.boost.org/LICENSE_1_0.txt)
5 
6 module elf.sections.symboltable;
7 
8 import std.exception;
9 import std.conv : to;
10 import elf, elf.low, elf.low32, elf.low64, elf.meta;
11 
12 static if (__VERSION__ >= 2079)
13 	alias elfEnforce = enforce!ELFException;
14 else
15 	alias elfEnforce = enforceEx!ELFException;
16 
17 
18 struct SymbolTable {
19 	private SymbolTableImpl m_impl;
20 
21 	this(ELFSection section) {
22 		if (section.bits == 32) {
23 			m_impl = new SymbolTable32Impl(section);
24 		} else {
25 			m_impl = new SymbolTable64Impl(section);
26 		}
27 	}
28 
29 	ELFSymbol getSymbolAt(size_t index) {
30 		return m_impl.getSymbolAt(index);
31 	}
32 
33 	auto symbols() {
34 		static struct Symbols {
35 			private SymbolTableImpl m_impl;
36 			private size_t m_currentIndex = 0;
37 
38 			@property bool empty() { return m_currentIndex >= m_impl.length; }
39 
40 			@property ELFSymbol front() {
41 				elfEnforce(!empty, "out of bounds exception");
42 				return m_impl.getSymbolAt(m_currentIndex);
43 			}
44 
45 			void popFront() {
46 				elfEnforce(!empty, "out of bounds exception");
47 				this.m_currentIndex++;
48 			}
49 
50 			@property typeof(this) save() {
51 				return this;
52 			}
53 
54 			this(SymbolTableImpl impl) {
55 				this.m_impl = impl;
56 			}
57 		}
58 
59 		return Symbols(this.m_impl);
60 	}
61 }
62 
63 private interface SymbolTableImpl {
64 	ELFSymbol getSymbolAt(size_t index);
65 	@property ulong length();
66 }
67 
68 private class SymbolTable32Impl : SymbolTableImpl {
69 	private ELFSection32 m_section;
70 
71 	this(ELFSection section) {
72 		elfEnforce(section.bits == 32);
73 		this(cast(ELFSection32) section);
74 	}
75 
76 	this(ELFSection32 section) {
77 		this.m_section = section;
78 	}
79 
80 	ELFSymbol getSymbolAt(size_t index) {
81 		elfEnforce(index * ELFSymbol32L.sizeof < m_section.size);
82 		ELFSymbol32L symbol;
83 		symbol = *cast(ELFSymbol32L*) m_section.contents[index * ELFSymbol32L.sizeof .. (index + 1) * ELFSymbol32L.sizeof].ptr;
84 		return new ELFSymbol32(m_section, symbol);
85 	}
86 
87 	@property ulong length() {
88 		return m_section.size / ELFSymbol32L.sizeof;
89 	}
90 }
91 
92 private class SymbolTable64Impl : SymbolTableImpl {
93 	private ELFSection64 m_section;
94 
95 	this(ELFSection section) {
96 		elfEnforce(section.bits == 64);
97 		this(cast(ELFSection64) section);
98 	}
99 
100 	this(ELFSection64 section) {
101 		this.m_section = section;
102 	}
103 
104 	ELFSymbol getSymbolAt(size_t index) {
105 		elfEnforce(index * ELFSymbol64L.sizeof < m_section.size);
106 		ELFSymbol64L symbol;
107 		symbol = *cast(ELFSymbol64L*) m_section.contents[index * ELFSymbol64L.sizeof .. (index + 1) * ELFSymbol64L.sizeof].ptr;
108 		return new ELFSymbol64(m_section, symbol);
109 	}
110 
111 	@property ulong length() {
112 		return m_section.size / ELFSymbol64L.sizeof;
113 	}
114 }
115 
116 abstract class ELFSymbol {
117 	private ELFSection m_section;
118 
119 	@property:
120 	@ReadFrom("name") ELF_Word nameIndex();
121 	@ReadFrom("info") ubyte info();
122 	@ReadFrom("other") ubyte other();
123 	@ReadFrom("shndx") ELF_Section sectionIndex();
124 	@ReadFrom("value") ELF_Addr value();
125 	@ReadFrom("size") ELF_XWord size();
126 
127 	string name() {
128 		StringTable strtab = StringTable(m_section.m_elf.sections[m_section.link()]);
129 		return strtab.getStringAt(nameIndex);
130 	}
131 
132 	SymbolBinding binding() {
133 		return cast(SymbolBinding) (this.info() >> 4);
134 	}
135 
136 	SymbolType type() {
137 		return cast(SymbolType) (this.info() & 0xF);
138 	}
139 }
140 
141 final class ELFSymbol32 : ELFSymbol {
142 	private ELFSymbol32L m_symbol;
143 	mixin(generateVirtualReads!(ELFSymbol, "m_symbol"));
144 
145 	this(ELFSection32 section, ELFSymbol32L symbol) {
146 		this.m_section = section;
147 		this.m_symbol = symbol;
148 	}
149 }
150 
151 final class ELFSymbol64 : ELFSymbol {
152 	private ELFSymbol64L m_symbol;
153 	mixin(generateVirtualReads!(ELFSymbol, "m_symbol"));
154 
155 	this(ELFSection64 section, ELFSymbol64L symbol) {
156 		this.m_section = section;
157 		this.m_symbol = symbol;
158 	}
159 }
160 
161 enum SymbolBinding {
162 	local = 0,
163 	global = 1,
164 	weak = 2,
165 	loproc = 13,
166 	hiproc = 15,
167 }
168 
169 enum SymbolType {
170 	notype = 0,
171 	object = 1,
172 	func = 2,
173 	section = 3,
174 	file = 4,
175 	loproc = 13,
176 	hiproc = 15,
177 }