1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
use common::{DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex};
use endianity::Endianity;
use read::{EndianSlice, Reader, ReaderOffset, Result, Section};
use Format;
/// The `DebugStr` struct represents the DWARF strings
/// found in the `.debug_str` section.
#[derive(Debug, Default, Clone, Copy)]
pub struct DebugStr<R: Reader> {
debug_str_section: R,
}
impl<'input, Endian> DebugStr<EndianSlice<'input, Endian>>
where
Endian: Endianity,
{
/// Construct a new `DebugStr` instance from the data in the `.debug_str`
/// section.
///
/// It is the caller's responsibility to read the `.debug_str` section and
/// present it as a `&[u8]` slice. That means using some ELF loader on
/// Linux, a Mach-O loader on OSX, etc.
///
/// ```
/// use gimli::{DebugStr, LittleEndian};
///
/// # let buf = [0x00, 0x01, 0x02, 0x03];
/// # let read_debug_str_section_somehow = || &buf;
/// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian);
/// ```
pub fn new(debug_str_section: &'input [u8], endian: Endian) -> Self {
Self::from(EndianSlice::new(debug_str_section, endian))
}
}
impl<R: Reader> DebugStr<R> {
/// Lookup a string from the `.debug_str` section by DebugStrOffset.
///
/// ```
/// use gimli::{DebugStr, DebugStrOffset, LittleEndian};
///
/// # let buf = [0x01, 0x02, 0x00];
/// # let offset = DebugStrOffset(0);
/// # let read_debug_str_section_somehow = || &buf;
/// # let debug_str_offset_somehow = || offset;
/// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian);
/// println!("Found string {:?}", debug_str.get_str(debug_str_offset_somehow()));
/// ```
pub fn get_str(&self, offset: DebugStrOffset<R::Offset>) -> Result<R> {
let input = &mut self.debug_str_section.clone();
input.skip(offset.0)?;
input.read_null_terminated_slice()
}
}
impl<R: Reader> Section<R> for DebugStr<R> {
fn section_name() -> &'static str {
".debug_str"
}
}
impl<R: Reader> From<R> for DebugStr<R> {
fn from(debug_str_section: R) -> Self {
DebugStr { debug_str_section }
}
}
/// The raw contents of the `.debug_str_offsets` section.
#[derive(Debug, Default, Clone, Copy)]
pub struct DebugStrOffsets<R: Reader> {
section: R,
}
impl<R: Reader> DebugStrOffsets<R> {
// TODO: add an iterator over the sets of entries in the section.
// This is not needed for common usage of the section though.
/// Returns the `.debug_str` offset at the given `base` and `index`.
///
/// A set of entries in the `.debug_str_offsets` section consists of a header
/// followed by a series of string table offsets.
///
/// The `base` must be the `DW_AT_str_offsets_base` value from the compilation unit DIE.
/// This is an offset that points to the first entry following the header.
///
/// The `index` is the value of a `DW_FORM_strx` attribute.
///
/// The `format` must be the DWARF format of the compilation unit. This format must
/// match the header. However, note that we do not parse the header to validate this,
/// since locating the header is unreliable, and the GNU extensions do not emit it.
pub fn get_str_offset(
&self,
format: Format,
base: DebugStrOffsetsBase<R::Offset>,
index: DebugStrOffsetsIndex<R::Offset>,
) -> Result<DebugStrOffset<R::Offset>> {
let input = &mut self.section.clone();
input.skip(base.0)?;
input.skip(R::Offset::from_u64(
index.0.into_u64() * u64::from(format.word_size()),
)?)?;
input.read_offset(format).map(DebugStrOffset)
}
}
impl<R: Reader> Section<R> for DebugStrOffsets<R> {
fn section_name() -> &'static str {
".debug_str_offsets"
}
}
impl<R: Reader> From<R> for DebugStrOffsets<R> {
fn from(section: R) -> Self {
DebugStrOffsets { section }
}
}
/// The `DebugLineStr` struct represents the DWARF strings
/// found in the `.debug_line_str` section.
#[derive(Debug, Default, Clone, Copy)]
pub struct DebugLineStr<R: Reader> {
section: R,
}
impl<R: Reader> DebugLineStr<R> {
/// Lookup a string from the `.debug_line_str` section by DebugLineStrOffset.
pub fn get_str(&self, offset: DebugLineStrOffset<R::Offset>) -> Result<R> {
let input = &mut self.section.clone();
input.skip(offset.0)?;
input.read_null_terminated_slice()
}
}
impl<R: Reader> Section<R> for DebugLineStr<R> {
fn section_name() -> &'static str {
".debug_line_str"
}
}
impl<R: Reader> From<R> for DebugLineStr<R> {
fn from(section: R) -> Self {
DebugLineStr { section }
}
}
#[cfg(test)]
mod tests {
extern crate test_assembler;
use self::test_assembler::{Endian, Label, LabelMaker, Section};
use super::*;
use test_util::GimliSectionMethods;
use LittleEndian;
#[test]
fn test_get_str_offset() {
for format in vec![Format::Dwarf32, Format::Dwarf64] {
let zero = Label::new();
let length = Label::new();
let start = Label::new();
let first = Label::new();
let end = Label::new();
let mut section = Section::with_endian(Endian::Little)
.mark(&zero)
.initial_length(format, &length, &start)
.D16(5)
.D16(0)
.mark(&first);
for i in 0..20 {
section = section.word(format.word_size(), 1000 + i);
}
section = section.mark(&end);
length.set_const((&end - &start) as u64);
let section = section.get_contents().unwrap();
let debug_str_offsets = DebugStrOffsets::from(EndianSlice::new(§ion, LittleEndian));
let base = DebugStrOffsetsBase((&first - &zero) as usize);
assert_eq!(
debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(0)),
Ok(DebugStrOffset(1000))
);
assert_eq!(
debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(19)),
Ok(DebugStrOffset(1019))
);
}
}
}