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
)))))
28 ;; -- elf-file -------------------------------------------------------------
30 ;; higher level structure for an elf file
32 ((elf-file-data :initform nil
:accessor elf-file-data-of
33 :documentation
"Raw binary data of file")
34 (header :accessor header-of
:initform nil
35 :documentation
"Header of file")
36 (sections :accessor sections-of
:initform nil
)))
38 ;; a few convienence methods to save needless repetition
40 (defmethod buffered-data-of ((elf elf-file
))
41 "Acess the binary data"
42 (buffered-data-of (slot-value elf
'elf-file-data
)))
44 (defmethod (setf buffered-data-of
) (value (elf elf-file
))
45 "Modify the binary data"
46 (setf (buffered-data-of (slot-value elf
'elf-file-data
))
49 (defmethod buffer-pos-of ((elf elf-file
))
50 "Access our point inside the binary data"
51 (buffer-pos-of (slot-value elf
'elf-file-data
)))
53 (defmethod (setf buffer-pos-of
) (value (elf elf-file
))
54 "Modify the point inside the binary data"
55 (setf (buffer-pos-of (slot-value elf
'elf-file-data
)) value
))
57 (defmacro elf-file-excursion
((elf-file pos
) &rest body
)
58 "Ecexcute body, with buffered-pos-of elf at pos then restore it"
60 (with-gensyms (old-pos)
62 ((,old-pos
(buffer-pos-of (buffered-data-of ,elf-file
))))
64 (buffer-pos-of ,elf-file
) ,pos
)
68 (buffer-pos-of ,elf-file
) ,old-pos
))))))
70 (defgeneric section-of
(elf index
))
72 (defmethod section-of ((elf elf-file
) index
)
73 (elt (sections-of elf
) index
))
75 (defgeneric (setf section-of
) (value elf index
))
77 (defmethod (setf section-of
) (value (elf elf-file
) index
)
78 (setf (elt (sections-of elf
) index
) value
))
80 (defgeneric advance-file-pointer
(elf advance
))
82 (defmethod advance-file-pointer ((elf elf-file
) advance
)
86 (setf (buffer-pos-of elf
)
89 ;; -- elf-section -------------------------------------------------------------
91 (defclass elf-section
()
92 (header :accessor header-of
:initform
0)
93 (elf-type :initform nil
)
94 (name :initform nil
:accessor name-of
)
95 (:documentation
"Object that represents a generic elf section"))
97 (defgeneric offset-of
(section))
99 (defmethod offset-of ((section elf-section
))
100 (sh-entsize-of (header-of section
)))
102 (defgeneric size-of
(section))
104 (defmethod size-of ((section elf-section
))
105 (length (buffered-data-of section
)))
107 (defgeneric elf-type-of
(section))
109 (defmethod elf-type-of ((section elf-section
))
110 (sh-type-of (header-of section
)))
112 (defclass elf-string-section
(elf-section)
114 :documentation
"Specialist class for elf string section")
116 (defclass elf-symbol-section
(elf-section)
118 :documentation
"Specialist class for elf symbol section")
120 (defclass elf-relinfo-section
(elf-section)
122 :documentation
"Specialist class for elf relocation info section")
124 (defclass elf-relainfo-section
(elf-section)
126 :documentation
"Speciallist class for elf address relocation info section")
129 ;; -entries -----------------------------------------------------------------------------
131 (defgeneric elf-entry-type-of
(section))
133 (defmethod elf-entry-type-of ((section elf-section
))
134 "Given the section, return the type used to read an entry from it via read-value"
136 ((section-entry-types
138 (+SHT_STRTAB
+ .
'asciiz
)
139 (+SHT_PROGBITS
+ .
'u8
)
140 (+SHT_NOTES
+ 'asciiz
)
141 (+SHT_SYMTAB
+ 'elf-sym
)
143 (+SHT_RELA
+ 'elf-rela
))))
145 (cdr (assoc (slot-value section
'elf-type
) section-entry-types
))
148 (defgeneric elf-entry-type-class-of
(section))
150 (defmethod elf-entry-type-class-of ((section elf-section
))
151 "Given the section, return the class that should be used to represent that section"
153 ((section-entry-classes
154 '((+SHT_NULL
+ 'elf-section
)
155 (+SHT_STRTAB
+ .
'elf-string-section
)
156 (+SHT_PROGBITS
+ .
'elf-section
)
157 (+SHT_NOTES
+ 'elf-string-section
)
158 (+SHT_SYMTAB
+ 'elf-symbol-section
)
159 (+SHT_REL
+ 'elf-relinfo-section
)
160 (+SHT_RELA
+ 'elf-relainfo-section
))))
162 (cdr (assoc (slot-value section
'elf-type
) section-entry-classes
))
165 (defgeneric get-entry
(section &key elf-file index offset
)
166 (:documentation
"Extract an entry from a section by index or offset"))
169 (defgeneric get-offset-from-index
(section index
))
171 (defmethod get-offset-from-index ((section elf-section
) index
)
172 "Given an index into a section calclate the offset it represents."
173 (* index
(entry-size-of section
)))
175 (defmacro with-real-offset
(real-offset-sym ( section index offset
) &rest body
)
176 "Use real-offset-sym to represent the actual offset represented by
177 either index or offset into the section in body."
179 `(let* ((,real-offset-sym
181 (* ,index
(entry-size-of ,section
))
185 ;; -- exctrating entries from sections ---------------------------------------------
188 (defmethod get-entry ((section elf-section
) &key elf-file index offset
)
189 "Retrieve an entry from an elf-section via either an index or an offset."
190 (declare (ignore elf-file
))
191 (assert (or (null offset
) (null index
)))
192 (assert (or offset index
))
193 ;; this will fire if you try to index an unindexable section
194 (assert (or (null index
)
196 (not (zerop (entry-size-of section
))))))
197 (with-real-offset real-offset
198 (section index offset
)
200 ((buffered-data-of section
) real-offset
)
202 (elf-entry-type-of section
)
203 (buffered-data-of section
)))))
205 ;; -- strings from string sections ---------------------------------------------------
207 (defmethod get-entry ((section elf-string-section
) &key elf-file index offset
)
208 "Retrieve an string from an appropiate section via an offset."
209 (call-next-method section
:elf-file elf-file
:index index
:offset offset
)
210 ;; you can't index these
211 (assert (and (integerp offset
) (null index
)))
213 ((buffered-data-of section
) offset
)
214 (read-value 'asciiz
(buffered-data-of section
))))
216 (defun make-entry-extractor (elf &key section-index
)
217 "Create and return a function to extract an entry from the given section."
219 (get-entry (section-of elf section-index
) :elf-file elf
:offset offset
)))
221 ;; -- symbol entries from symbol sections -----------------------------------------
223 (defclass elf-symbol
()
224 ((name :initarg
:name
:reader name-of
)
225 (entry :initarg
:entry
:reader entry-of
)))
227 (defmethod get-entry ((section elf-symbol-section
) &key elf-file index offset
)
228 "Extract a symbol from a symbol section."
229 (let* ((elf-symbol (call-next-method section
:elf-file elf-file
:index index
:offset offset
))
231 (make-entry-extractor
233 :section-index
(sh-link-of (header-of section
)))))
234 (make-instance 'elf-symbol
236 (funcall string-extractor
(st-name-of elf-symbol
))
237 ;; to do - things with value, size, etc?
242 ;; -- relocation info entries from relocation info sections -------------------------
244 (defclass elf-rel-info
()
245 ((rel-section-index :accessor rel-section-index-of
246 :initarg
:rel-section-index
247 :documentation
"Index of section this relocation affects.")
248 (offset :accessor offset-of
250 :documentation
"Offset into section where relocation is applied")
251 (relocation-type :accessor relocation-type-of
252 :initarg
:relocation-type
253 :documentation
"Type of relocation to apply")
254 (symbol :accessor symbol-of
256 :documentation
"Symbol associated with this relocation.")))
258 (defgeneric make-rel-entry
(elf-rel-info-entry &key section elf-file
))
260 (defmethod make-rel-entry ((elf-rel-info-entry elf-rel-info
) &key section elf-file
)
262 ((rel-type (rel-entry)
263 (logand (r-info-of rel-entry
) #XFF
))
265 (ash (r-info-of rel-entry
) -
8)))
266 (make-instance 'elf-rel-info
267 :rel-section-index
(sh-info-of (header-of section
))
268 :offset
(r-offset-of elf-rel-info-entry
)
271 (sh-link-of (header-of section
)))
272 :index
(rel-sym elf-rel-info-entry
))
273 :type
(rel-type elf-rel-info-entry
))))
275 ;; -- relocation info entries with addends from relocation info sections -----------------
277 (defmethod get-entry ((section elf-relinfo-section
) &key elf-file index offset
)
278 "Extract a relocation symbol from a relocation section"
279 (let ((elf-rel-info-entry
280 (call-next-method section
:elf-file elf-file
283 (make-rel-entry elf-rel-info-entry
288 (defclass elf-rela-info
(elf-rel-info)
292 (:documentation
"Represents a relocation info record with an addend"))
294 (defmethod update-instance-for-different-class :after
((old elf-rel-info
)
297 "Convert a plain relocation record into one with an addend."
298 (setf (addend-of new
) addend
))
300 (defmethod make-rel-entry ((rel-entry elf-rela-info
) &key section elf-file
)
301 (let ((result (call-next-method rel-entry
:section section
:elf-file elf-file
)))
302 (change-class result
'elf-rela-info
:addend
(r-addend-of result
))))
304 (defmethod get-entry ((section elf-relainfo-section
) &key elf-file index offset
)
305 "Extract a relocation symbol from a relocation section with addends"
306 (let* ((elf-rela-info-entry
307 (call-next-method section
:elf-file elf-file
310 (result (make-rel-entry elf-rela-info-entry
319 ;; --- extract name of a section --------------------------------------------------
321 (defgeneric elf-section-name
(elf index
))
323 (defmethod elf-section-name ((elf elf-file
) index
)
324 "Return the name of a section, given the index."
326 ((string-section-index (e-shstrndx-of (header-of elf
))))
327 (get-entry (aref (sections-of elf
) string-section-index
)
328 :offset
(sh-name-of (aref (sections-of elf
) index
)))))
331 ;; actually read an elf file --------------------------------------------------------
334 (defmethod initialize-instance :after
((elf elf-file
) &key filepath
)
335 "Actually read an elf file and process the sections."
338 (format *debug-io
* "Reading elf file data~%")
339 (setf (elf-file-data-of elf
)
340 (make-instance 'elf-file-data
:filepath filepath
)))
343 "Read and set the elf file header"
345 ((elf-data (elf-file-data-of elf
)))
346 (setf (buffer-pos-of elf-data
) 0)
347 (setf (header-of elf
)
348 (read-value 'elf-header elf-data
))))
350 ;; create n empty sections for each section in the elf file
351 (create-sections (section-count)
352 "Create the sections in the elf file"
353 (setf (sections-of elf
) (make-array section-count
))
355 for section-index from
0 below section-count
356 do
(setf (section-of elf section-index
)
357 (make-instance 'elf-section
))))
359 ;; to do -- compute entry type
360 (fill-section-header-slots (section)
361 "Given a section header, fill in she slots in the section object"
362 (setf (entry-size-of section
) (sh-entsize-of (header-of section
)))
363 ;; just grab the raw binary for the section from the elf
364 (setf (buffered-data-of section
)
365 (subseq (buffered-data-of elf
)
367 (+ (offset-of section
)
368 (size-of section
)))))
370 ;; read each section header and use the info in it to set the
371 ;; clos elf-section object slots
372 (read-section-headers ()
373 (let ((elf-header (header-of elf
)))
375 for section-index from
0 below
(e-shnum-of elf-header
)
376 for section-offset
= (e-shoff-of elf-header
) then
377 (+ section-offset
(e-shentsize-of elf-header
))
379 (let ((section (section-of elf section-index
)))
380 (setf (buffer-pos-of elf
) section-offset
)
381 ;; read the section header from the raw elf data
382 (setf (header-of section
)
383 (read-value 'elf32-section-header
(elf-file-data-of elf
)))
384 (fill-section-header-slots section
)
385 (change-class section
(elf-entry-type-class-of section
))))))
387 (set-section-names ()
389 for section-index from
0 below
(e-shnum-of (header-of elf
))
390 do
(setf (name-of (section-of elf section-index
))
391 (elf-section-name elf section-index
)))))
395 ;; defmethod read-elf file
398 (create-sections (e-shnum-of (header-of elf
)))
399 (read-section-headers)))