4 (declaim (optimize (debug 3)
9 ;; -- handy things ----------------------------------------------------------
11 (defmacro once-only
((&rest names
) &body body
)
12 (let ((gensyms (loop for n in names collect
(gensym))))
13 `(let (,@(loop for g in gensyms collect
`(,g
(gensym))))
14 `(let (,,@(loop for g in gensyms for n in names collect
``(,,g
,,n
)))
15 ,(let (,@(loop for n in names for g in gensyms collect
`(,n
,g
)))
18 (defmacro with-gensyms
((&rest names
) &body body
)
19 `(let ,(loop for n in names collect
`(,n
(gensym)))
22 (defun remove-nils (lst)
23 "eliminate elements where nil"
25 (dolist (x lst
(nreverse acc
))
26 (when x
(push x acc
)))))
29 (defgeneric section-of
(elf index
))
31 (defgeneric (setf section-of
) (value elf index
))
33 (defgeneric offset-of
(section))
35 (defgeneric entry-size-of
(section))
37 (defgeneric size-of
(section))
39 (defgeneric elf-type-of
(section))
41 (defgeneric elf-entry-type-of
(section))
43 (defgeneric elf-entry-type-class-of
(section))
45 (defgeneric get-entry
(section &key elf-file index offset
)
46 (:documentation
"Extract an entry from a section by index or offset"))
48 (defgeneric get-offset-from-index
(section index
))
50 (defgeneric make-rel-entry
(elf-rel-info-entry &key section elf-file
))
52 (defgeneric elf-section-name
(elf index
))
54 ;; -- elf-file -------------------------------------------------------------
56 ;; higher level structure for an elf file
57 (defclass elf-file
(buffered-data-mixin)
58 ((header :accessor header-of
:initform nil
59 :documentation
"Header of file")
60 (sections :accessor sections-of
:initform
61 (make-array 0 :adjustable t
:fill-pointer
0))))
63 ;; a few convienence methods to save needless repetition
66 (defmacro buffered-data-excursion
((buffer pos
) &rest body
)
67 "Ecexcute body, with buffered-pos-of elf at pos then restore it"
69 (with-gensyms (old-pos)
71 ((,old-pos
(buffer-pos-of ,buffer
)))
73 (buffer-pos-of ,buffer
) ,pos
)
77 (buffer-pos-of ,buffer
) ,old-pos
))))))
79 (defmethod section-of ((elf elf-file
) index
)
80 (elt (sections-of elf
) index
))
82 (defmethod (setf section-of
) (value (elf elf-file
) index
)
83 (setf (elt (sections-of elf
) index
) value
))
86 ;; -- elf-section -------------------------------------------------------------
88 (defclass elf-section
(buffered-data-mixin)
89 ((header :accessor header-of
:initform
0)
90 (name :initform nil
:accessor name-of
))
91 (:documentation
"Object that represents a generic elf section"))
94 (defmethod offset-of ((section elf-section
))
95 "Return the offset to the actual section data in the file."
96 (sh-offset-of (header-of section
)))
98 (defmethod entry-size-of ((section elf-section
))
99 (sh-entsize-of (header-of section
)))
101 (defmethod size-of ((section elf-section
))
102 (sh-size-of (header-of section
)))
104 (defmethod initialize-instance :after
((section elf-section
) &key elf index
)
105 (check-type elf elf-file
)
106 (let* ((elf-header (header-of elf
))
107 (section-header-offset
108 (+ (e-shoff-of elf-header
)
109 (* index
(e-shentsize-of elf-header
)))))
110 ;; move buffer pointer to start of section header
111 (setf (buffer-pos-of elf
)
112 section-header-offset
)
113 ;; read in the section header
114 (setf (header-of section
)
115 (read-value 'elf32-section-header elf
))
116 ;; grab the actual section itself now we know where it is via header
117 (setf (buffered-data-of section
)
118 (subseq (buffered-data-of elf
)
120 (+ (offset-of section
)
121 (size-of section
))))))
124 (defmethod elf-type-of ((section elf-section
))
125 (sh-type-of (header-of section
)))
127 (defclass elf-string-section
(elf-section)
129 (:documentation
"Specialist class for elf string section"))
131 (defclass elf-symbol-section
(elf-section)
133 (:documentation
"Specialist class for elf symbol section"))
135 (defclass elf-relinfo-section
(elf-section)
137 (:documentation
"Specialist class for elf relocation info section"))
139 (defclass elf-relainfo-section
(elf-section)
141 (:documentation
"Speciallist class for elf address relocation info section"))
144 ;; -entries -----------------------------------------------------------------------------
147 (defmethod elf-entry-type-of ((section elf-section
))
148 "Given the section, return the type used to read an entry from it via read-value"
150 ((section-entry-types
151 (list (cons +SHT_NULL
+ 'u8
)
152 (cons +SHT_STRTAB
+ 'asciiz
)
153 (cons +SHT_PROGBITS
+ 'u8
)
154 (cons +SHT_NOTE
+ 'asciiz
)
155 (cons +SHT_SYMTAB
+ 'elf-sym
)
156 (cons +SHT_REL
+ 'elf-rel
)
157 (cons +SHT_RELA
+ 'elf-rela
))))
159 (cdr (assoc (elf-type-of section
) section-entry-types
))
163 (defmethod elf-entry-type-class-of ((section elf-section
))
164 "Given the section, return the class that should be used to represent that section"
166 ((section-entry-classes
167 (list (cons +SHT_NULL
+ 'elf-section
)
168 (cons +SHT_STRTAB
+ 'elf-string-section
)
169 (cons +SHT_PROGBITS
+ 'elf-section
)
170 (cons +SHT_NOTE
+ 'elf-string-section
)
171 (cons +SHT_SYMTAB
+ 'elf-symbol-section
)
172 (cons +SHT_REL
+ 'elf-relinfo-section
)
173 (cons +SHT_RELA
+ 'elf-relainfo-section
))))
175 (cdr (assoc (elf-type-of section
) section-entry-classes
))
179 (defmethod get-offset-from-index ((section elf-section
) index
)
180 "Given an index into a section calclate the offset it represents."
181 (* index
(entry-size-of section
)))
183 (defmacro with-real-offset
(real-offset-sym (section index offset
) &rest body
)
184 "Use real-offset-sym to represent the actual offset represented by
185 either index or offset into the section in body."
187 `(let* ((,real-offset-sym
189 (* ,index
(entry-size-of ,section
))
193 ;; -- exctrating entries from sections ---------------------------------------------
196 (defmethod get-entry ((section elf-section
) &key elf-file index offset
)
197 "Retrieve an entry from an elf-section via either an index or an offset."
198 (declare (ignore elf-file
))
199 (assert (or (null offset
) (null index
)))
200 (assert (or offset index
))
201 ;; this will fire if you try to index an unindexable section
202 (assert (or (null index
)
204 (not (zerop (entry-size-of section
))))))
205 (with-real-offset real-offset
206 (section index offset
)
207 (buffered-data-excursion
208 (section real-offset
)
210 (elf-entry-type-of section
)
213 ;; -- strings from string sections ---------------------------------------------------
215 (defmethod get-entry ((section elf-string-section
) &key elf-file index offset
)
216 "Retrieve an string from an appropiate section via an offset."
217 (call-next-method section
:elf-file elf-file
:index index
:offset offset
)
218 ;; you can't index these
219 (assert (and (integerp offset
) (null index
)))
220 (buffered-data-excursion
222 (read-value 'asciiz section
)))
224 (defun make-entry-extractor (elf &key section-index
)
225 "Create and return a function to extract an entry from the given section."
227 (get-entry (section-of elf section-index
) :elf-file elf
:offset offset
)))
229 ;; -- symbol entries from symbol sections -----------------------------------------
231 (defclass elf-symbol
()
232 ((name :initarg
:name
:reader name-of
)
233 (entry :initarg
:entry
:reader entry-of
)))
235 (defmethod get-entry ((section elf-symbol-section
) &key elf-file index offset
)
236 "Extract a symbol from a symbol section."
237 (let* ((elf-symbol (call-next-method section
:elf-file elf-file
:index index
:offset offset
))
239 (make-entry-extractor
241 :section-index
(sh-link-of (header-of section
)))))
242 (make-instance 'elf-symbol
244 (funcall string-extractor
(st-name-of elf-symbol
))
245 ;; to do - things with value, size, etc?
250 ;; -- relocation info entries from relocation info sections -------------------------
252 (defclass elf-rel-info
()
253 ((rel-section-index :accessor rel-section-index-of
254 :initarg
:rel-section-index
255 :documentation
"Index of section this relocation affects.")
256 (offset :accessor offset-of
258 :documentation
"Offset into section where relocation is applied")
259 (relocation-type :accessor relocation-type-of
260 :initarg
:relocation-type
261 :documentation
"Type of relocation to apply")
262 (symbol :accessor symbol-of
264 :documentation
"Symbol associated with this relocation.")))
267 (defmethod make-rel-entry ((elf-rel-info-entry elf-rel-info
) &key section elf-file
)
269 ((rel-type (rel-entry)
270 (logand (r-info-of rel-entry
) #XFF
))
272 (ash (r-info-of rel-entry
) -
8)))
273 (make-instance 'elf-rel-info
274 :rel-section-index
(sh-info-of (header-of section
))
275 :offset
(r-offset-of elf-rel-info-entry
)
278 (sh-link-of (header-of section
)))
279 :index
(rel-sym elf-rel-info-entry
))
280 :type
(rel-type elf-rel-info-entry
))))
282 ;; -- relocation info entries with addends from relocation info sections -----------------
284 (defmethod get-entry ((section elf-relinfo-section
) &key elf-file index offset
)
285 "Extract a relocation symbol from a relocation section"
286 (let ((elf-rel-info-entry
287 (call-next-method section
:elf-file elf-file
290 (make-rel-entry elf-rel-info-entry
295 (defclass elf-rela-info
(elf-rel-info)
299 (:documentation
"Represents a relocation info record with an addend"))
301 (defmethod update-instance-for-different-class :after
((old elf-rel-info
)
304 "Convert a plain relocation record into one with an addend."
305 (setf (addend-of new
) addend
))
307 (defmethod make-rel-entry ((rel-entry elf-rela-info
) &key section elf-file
)
308 (let ((result (call-next-method rel-entry
:section section
:elf-file elf-file
)))
309 (change-class result
'elf-rela-info
:addend
(r-addend-of result
))))
311 (defmethod get-entry ((section elf-relainfo-section
) &key elf-file index offset
)
312 "Extract a relocation symbol from a relocation section with addends"
313 (let* ((elf-rela-info-entry
314 (call-next-method section
:elf-file elf-file
317 (result (make-rel-entry elf-rela-info-entry
324 ;; --- extract name of a section --------------------------------------------------
327 (defmethod elf-section-name ((elf elf-file
) index
)
328 "Return the name of a section, given the index."
330 ((string-section-index (e-shstrndx-of (header-of elf
))))
331 (get-entry (aref (sections-of elf
) string-section-index
)
332 :offset
(sh-name-of (header-of (aref (sections-of elf
) index
))))))
335 ;; actually read an elf file --------------------------------------------------------
338 (defmethod initialize-instance :after
((elf elf-file
) &key filepath
)
339 "Actually read an elf file and process the sections."
342 "Read and set the elf file header"
343 (setf (buffer-pos-of elf
) 0)
344 (setf (header-of elf
)
345 (read-value 'elf-header elf
)))
347 ;; create n empty sections for each section in the elf file
348 (create-sections (section-count)
349 "Create the sections in the elf file, specialising them as we go along."
351 for section-index from
0 below section-count
353 ((section (make-instance 'elf-section
:elf elf
:index section-index
)))
354 (change-class section
(elf-entry-type-class-of section
))
355 (vector-push-extend section
(sections-of elf
)))))
357 (set-section-names ()
359 for section-index from
0 below
(e-shnum-of (header-of elf
))
360 do
(let ((section (section-of elf section-index
)))
361 (setf (name-of section
)
362 (elf-section-name elf section-index
))))))
365 ;; defmethod read-elf file
366 (read-buffered-data elf
:filepath filepath
)
368 (create-sections (e-shnum-of (header-of elf
)))))