2 DebugLineStrOffset
, DebugStrOffset
, DebugStrOffsetsBase
, DebugStrOffsetsIndex
, DwarfFileType
,
5 use crate::endianity
::Endianity
;
6 use crate::read
::{EndianSlice, Reader, ReaderOffset, Result, Section}
;
9 /// The `DebugStr` struct represents the DWARF strings
10 /// found in the `.debug_str` section.
11 #[derive(Debug, Default, Clone, Copy)]
12 pub struct DebugStr
<R
> {
16 impl<'input
, Endian
> DebugStr
<EndianSlice
<'input
, Endian
>>
20 /// Construct a new `DebugStr` instance from the data in the `.debug_str`
23 /// It is the caller's responsibility to read the `.debug_str` section and
24 /// present it as a `&[u8]` slice. That means using some ELF loader on
25 /// Linux, a Mach-O loader on macOS, etc.
28 /// use gimli::{DebugStr, LittleEndian};
30 /// # let buf = [0x00, 0x01, 0x02, 0x03];
31 /// # let read_debug_str_section_somehow = || &buf;
32 /// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian);
34 pub fn new(debug_str_section
: &'input
[u8], endian
: Endian
) -> Self {
35 Self::from(EndianSlice
::new(debug_str_section
, endian
))
39 impl<R
: Reader
> DebugStr
<R
> {
40 /// Lookup a string from the `.debug_str` section by DebugStrOffset.
43 /// use gimli::{DebugStr, DebugStrOffset, LittleEndian};
45 /// # let buf = [0x01, 0x02, 0x00];
46 /// # let offset = DebugStrOffset(0);
47 /// # let read_debug_str_section_somehow = || &buf;
48 /// # let debug_str_offset_somehow = || offset;
49 /// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian);
50 /// println!("Found string {:?}", debug_str.get_str(debug_str_offset_somehow()));
52 pub fn get_str(&self, offset
: DebugStrOffset
<R
::Offset
>) -> Result
<R
> {
53 let input
= &mut self.debug_str_section
.clone();
54 input
.skip(offset
.0)?
;
55 input
.read_null_terminated_slice()
60 /// Create a `DebugStr` section that references the data in `self`.
62 /// This is useful when `R` implements `Reader` but `T` does not.
67 /// # let load_section = || unimplemented!();
68 /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
69 /// let owned_section: gimli::DebugStr<Vec<u8>> = load_section();
70 /// // Create a reference to the DWARF section.
71 /// let section = owned_section.borrow(|section| {
72 /// gimli::EndianSlice::new(§ion, gimli::LittleEndian)
75 pub fn borrow
<'a
, F
, R
>(&'a
self, mut borrow
: F
) -> DebugStr
<R
>
79 borrow(&self.debug_str_section
).into()
83 impl<R
> Section
<R
> for DebugStr
<R
> {
84 fn id() -> SectionId
{
88 fn reader(&self) -> &R
{
89 &self.debug_str_section
93 impl<R
> From
<R
> for DebugStr
<R
> {
94 fn from(debug_str_section
: R
) -> Self {
95 DebugStr { debug_str_section }
99 /// The raw contents of the `.debug_str_offsets` section.
100 #[derive(Debug, Default, Clone, Copy)]
101 pub struct DebugStrOffsets
<R
> {
105 impl<R
: Reader
> DebugStrOffsets
<R
> {
106 // TODO: add an iterator over the sets of entries in the section.
107 // This is not needed for common usage of the section though.
109 /// Returns the `.debug_str` offset at the given `base` and `index`.
111 /// A set of entries in the `.debug_str_offsets` section consists of a header
112 /// followed by a series of string table offsets.
114 /// The `base` must be the `DW_AT_str_offsets_base` value from the compilation unit DIE.
115 /// This is an offset that points to the first entry following the header.
117 /// The `index` is the value of a `DW_FORM_strx` attribute.
119 /// The `format` must be the DWARF format of the compilation unit. This format must
120 /// match the header. However, note that we do not parse the header to validate this,
121 /// since locating the header is unreliable, and the GNU extensions do not emit it.
122 pub fn get_str_offset(
125 base
: DebugStrOffsetsBase
<R
::Offset
>,
126 index
: DebugStrOffsetsIndex
<R
::Offset
>,
127 ) -> Result
<DebugStrOffset
<R
::Offset
>> {
128 let input
= &mut self.section
.clone();
130 input
.skip(R
::Offset
::from_u64(
131 index
.0.into_u
64() * u64::from(format
.word_size()),
133 input
.read_offset(format
).map(DebugStrOffset
)
137 impl<T
> DebugStrOffsets
<T
> {
138 /// Create a `DebugStrOffsets` section that references the data in `self`.
140 /// This is useful when `R` implements `Reader` but `T` does not.
145 /// # let load_section = || unimplemented!();
146 /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
147 /// let owned_section: gimli::DebugStrOffsets<Vec<u8>> = load_section();
148 /// // Create a reference to the DWARF section.
149 /// let section = owned_section.borrow(|section| {
150 /// gimli::EndianSlice::new(§ion, gimli::LittleEndian)
153 pub fn borrow
<'a
, F
, R
>(&'a
self, mut borrow
: F
) -> DebugStrOffsets
<R
>
155 F
: FnMut(&'a T
) -> R
,
157 borrow(&self.section
).into()
161 impl<R
> Section
<R
> for DebugStrOffsets
<R
> {
162 fn id() -> SectionId
{
163 SectionId
::DebugStrOffsets
166 fn reader(&self) -> &R
{
171 impl<R
> From
<R
> for DebugStrOffsets
<R
> {
172 fn from(section
: R
) -> Self {
173 DebugStrOffsets { section }
177 impl<Offset
> DebugStrOffsetsBase
<Offset
>
179 Offset
: ReaderOffset
,
181 /// Returns a `DebugStrOffsetsBase` with the default value of DW_AT_str_offsets_base
182 /// for the given `Encoding` and `DwarfFileType`.
183 pub fn default_for_encoding_and_file(
185 file_type
: DwarfFileType
,
186 ) -> DebugStrOffsetsBase
<Offset
> {
187 if encoding
.version
>= 5 && file_type
== DwarfFileType
::Dwo
{
188 // In .dwo files, the compiler omits the DW_AT_str_offsets_base attribute (because there is
189 // only a single unit in the file) but we must skip past the header, which the attribute
190 // would normally do for us.
191 // initial_length_size + version + 2 bytes of padding.
192 DebugStrOffsetsBase(Offset
::from_u8(
193 encoding
.format
.initial_length_size() + 2 + 2,
196 DebugStrOffsetsBase(Offset
::from_u8(0))
201 /// The `DebugLineStr` struct represents the DWARF strings
202 /// found in the `.debug_line_str` section.
203 #[derive(Debug, Default, Clone, Copy)]
204 pub struct DebugLineStr
<R
> {
208 impl<'input
, Endian
> DebugLineStr
<EndianSlice
<'input
, Endian
>>
212 /// Construct a new `DebugLineStr` instance from the data in the `.debug_line_str`
215 /// It is the caller's responsibility to read the `.debug_line_str` section and
216 /// present it as a `&[u8]` slice. That means using some ELF loader on
217 /// Linux, a Mach-O loader on macOS, etc.
220 /// use gimli::{DebugLineStr, LittleEndian};
222 /// # let buf = [0x00, 0x01, 0x02, 0x03];
223 /// # let read_debug_line_str_section_somehow = || &buf;
224 /// let debug_str = DebugLineStr::new(read_debug_line_str_section_somehow(), LittleEndian);
226 pub fn new(debug_line_str_section
: &'input
[u8], endian
: Endian
) -> Self {
227 Self::from(EndianSlice
::new(debug_line_str_section
, endian
))
231 impl<R
: Reader
> DebugLineStr
<R
> {
232 /// Lookup a string from the `.debug_line_str` section by DebugLineStrOffset.
233 pub fn get_str(&self, offset
: DebugLineStrOffset
<R
::Offset
>) -> Result
<R
> {
234 let input
= &mut self.section
.clone();
235 input
.skip(offset
.0)?
;
236 input
.read_null_terminated_slice()
240 impl<T
> DebugLineStr
<T
> {
241 /// Create a `DebugLineStr` section that references the data in `self`.
243 /// This is useful when `R` implements `Reader` but `T` does not.
248 /// # let load_section = || unimplemented!();
249 /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
250 /// let owned_section: gimli::DebugLineStr<Vec<u8>> = load_section();
251 /// // Create a reference to the DWARF section.
252 /// let section = owned_section.borrow(|section| {
253 /// gimli::EndianSlice::new(§ion, gimli::LittleEndian)
256 pub fn borrow
<'a
, F
, R
>(&'a
self, mut borrow
: F
) -> DebugLineStr
<R
>
258 F
: FnMut(&'a T
) -> R
,
260 borrow(&self.section
).into()
264 impl<R
> Section
<R
> for DebugLineStr
<R
> {
265 fn id() -> SectionId
{
266 SectionId
::DebugLineStr
269 fn reader(&self) -> &R
{
274 impl<R
> From
<R
> for DebugLineStr
<R
> {
275 fn from(section
: R
) -> Self {
276 DebugLineStr { section }
283 use crate::test_util
::GimliSectionMethods
;
284 use crate::LittleEndian
;
285 use test_assembler
::{Endian, Label, LabelMaker, Section}
;
288 fn test_get_str_offset() {
289 for format
in vec
![Format
::Dwarf32
, Format
::Dwarf64
] {
290 let zero
= Label
::new();
291 let length
= Label
::new();
292 let start
= Label
::new();
293 let first
= Label
::new();
294 let end
= Label
::new();
295 let mut section
= Section
::with_endian(Endian
::Little
)
297 .initial_length(format
, &length
, &start
)
302 section
= section
.word(format
.word_size(), 1000 + i
);
304 section
= section
.mark(&end
);
305 length
.set_const((&end
- &start
) as u64);
307 let section
= section
.get_contents().unwrap();
308 let debug_str_offsets
= DebugStrOffsets
::from(EndianSlice
::new(§ion
, LittleEndian
));
309 let base
= DebugStrOffsetsBase((&first
- &zero
) as usize);
312 debug_str_offsets
.get_str_offset(format
, base
, DebugStrOffsetsIndex(0)),
313 Ok(DebugStrOffset(1000))
316 debug_str_offsets
.get_str_offset(format
, base
, DebugStrOffsetsIndex(19)),
317 Ok(DebugStrOffset(1019))