Skip to content

Commit b8f401b

Browse files
authored
Make the .mdebug line parser support EE-GCC (PS2) (#362)
1 parent 282783c commit b8f401b

3 files changed

Lines changed: 107 additions & 16 deletions

File tree

objdiff-core/src/obj/mdebug.rs

Lines changed: 82 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const FDR_SIZE: usize = 0x48;
1010
const PDR_SIZE: usize = 0x34;
1111
const SYMR_SIZE: usize = 0x0c;
1212

13+
const ST_LABEL: u8 = 5;
1314
const ST_PROC: u8 = 6;
1415
const ST_STATICPROC: u8 = 14;
1516
const ST_END: u8 = 8;
@@ -40,6 +41,8 @@ pub(super) fn parse_line_info_mdebug(
4041
)?;
4142
let symbols = parse_symbols(symbols_data, endianness)?;
4243

44+
let strings_data = slice_at(data, header.cb_ss_offset, header.iss_max, section_file_offset)?;
45+
4346
let fdr_data = slice_at(
4447
data,
4548
header.cb_fd_offset,
@@ -63,11 +66,13 @@ pub(super) fn parse_line_info_mdebug(
6366
continue;
6467
}
6568

69+
assign_label_lines(sections, &symbols[sym_base..sym_end], strings_data, &fdr);
70+
6671
let Some(line_file_offset) = header.cb_line_offset.checked_add(fdr.cb_line_offset) else {
6772
continue;
6873
};
6974
let Some(line_file_base) =
70-
resolve_offset(line_file_offset, data.len(), section_file_offset)
75+
resolve_offset(line_file_offset, fdr.cb_line as usize, data.len(), section_file_offset)
7176
else {
7277
continue;
7378
};
@@ -168,6 +173,44 @@ fn assign_lines(sections: &mut [Section], base_address: u64, lines: &[i32]) {
168173
}
169174
}
170175

176+
fn assign_label_lines(
177+
sections: &mut [Section],
178+
symbols: &[SymbolEntry],
179+
strings: &[u8],
180+
fdr: &FileDescriptor,
181+
) {
182+
for sym in symbols {
183+
if sym.st != ST_LABEL || sym.index == 0 {
184+
continue;
185+
}
186+
let Some(name) = symbol_name(strings, fdr.iss_base, sym.iss) else {
187+
continue;
188+
};
189+
if !name.starts_with("$LM") {
190+
continue;
191+
}
192+
let address = fdr.adr as u64 + sym.value as u64;
193+
if let Some(section) = find_code_section(sections, address) {
194+
section.line_info.insert(address, sym.index);
195+
}
196+
}
197+
}
198+
199+
fn symbol_name(strings: &[u8], file_string_base: u32, string_offset: u32) -> Option<&str> {
200+
let offset =
201+
string_offset.try_into().ok().filter(|&offset: &usize| offset < strings.len()).or_else(
202+
|| {
203+
file_string_base
204+
.checked_add(string_offset)?
205+
.try_into()
206+
.ok()
207+
.filter(|&offset: &usize| offset < strings.len())
208+
},
209+
)?;
210+
let end = offset + strings[offset..].iter().position(|&b| b == 0)?;
211+
core::str::from_utf8(&strings[offset..end]).ok()
212+
}
213+
171214
fn find_code_section(sections: &mut [Section], address: u64) -> Option<&mut Section> {
172215
sections.iter_mut().find(|section| {
173216
section.kind == SectionKind::Code
@@ -209,12 +252,12 @@ fn slice_at(
209252
let size = size as usize;
210253
if size == 0 {
211254
ensure!(
212-
resolve_offset(offset, data.len(), section_file_offset).is_some(),
255+
resolve_offset(offset, 0, data.len(), section_file_offset).is_some(),
213256
"offset outside of .mdebug section"
214257
);
215258
return Ok(&data[0..0]);
216259
}
217-
let Some(offset) = resolve_offset(offset, data.len(), section_file_offset) else {
260+
let Some(offset) = resolve_offset(offset, size, data.len(), section_file_offset) else {
218261
bail!("offset outside of .mdebug section");
219262
};
220263
let end = offset.checked_add(size).context("range overflow")?;
@@ -224,26 +267,29 @@ fn slice_at(
224267

225268
fn resolve_offset(
226269
offset: u32,
270+
size: usize,
227271
data_len: usize,
228272
section_file_offset: Option<usize>,
229273
) -> Option<usize> {
230274
let offset = offset as usize;
231-
if offset <= data_len {
232-
Some(offset)
233-
} else if let Some(file_offset) = section_file_offset {
234-
offset.checked_sub(file_offset).filter(|rel| *rel <= data_len)
235-
} else {
236-
None
275+
if let Some(file_offset) = section_file_offset
276+
&& let Some(rel) = offset.checked_sub(file_offset)
277+
&& rel.checked_add(size).is_some_and(|end| end <= data_len)
278+
{
279+
return Some(rel);
237280
}
281+
offset.checked_add(size).filter(|&end| end <= data_len).map(|_| offset)
238282
}
239283

240284
#[derive(Clone, Copy)]
241285
struct Header {
242286
cb_line_offset: u32,
243287
cb_pd_offset: u32,
244288
cb_sym_offset: u32,
289+
cb_ss_offset: u32,
245290
cb_fd_offset: u32,
246291
isym_max: u32,
292+
iss_max: u32,
247293
ifd_max: u32,
248294
}
249295

@@ -267,8 +313,8 @@ impl Header {
267313
let _cb_opt_offset = read_u32(data, &mut cursor, endianness)?;
268314
let _iaux_max = read_u32(data, &mut cursor, endianness)?;
269315
let _cb_aux_offset = read_u32(data, &mut cursor, endianness)?;
270-
let _iss_max = read_u32(data, &mut cursor, endianness)?;
271-
let _cb_ss_offset = read_u32(data, &mut cursor, endianness)?;
316+
let iss_max = read_u32(data, &mut cursor, endianness)?;
317+
let cb_ss_offset = read_u32(data, &mut cursor, endianness)?;
272318
let _iss_ext_max = read_u32(data, &mut cursor, endianness)?;
273319
let _cb_ss_ext_offset = read_u32(data, &mut cursor, endianness)?;
274320
let ifd_max = read_u32(data, &mut cursor, endianness)?;
@@ -278,13 +324,23 @@ impl Header {
278324
let _iext_max = read_u32(data, &mut cursor, endianness)?;
279325
let _cb_ext_offset = read_u32(data, &mut cursor, endianness)?;
280326

281-
Ok(Header { cb_line_offset, cb_pd_offset, cb_sym_offset, cb_fd_offset, isym_max, ifd_max })
327+
Ok(Header {
328+
cb_line_offset,
329+
cb_pd_offset,
330+
cb_sym_offset,
331+
cb_ss_offset,
332+
cb_fd_offset,
333+
isym_max,
334+
iss_max,
335+
ifd_max,
336+
})
282337
}
283338
}
284339

285340
#[derive(Clone, Copy)]
286341
struct FileDescriptor {
287342
adr: u32,
343+
iss_base: u32,
288344
isym_base: u32,
289345
csym: u32,
290346
ipd_first: u16,
@@ -299,7 +355,7 @@ impl FileDescriptor {
299355
let mut cursor = 0;
300356
let adr = read_u32(data, &mut cursor, endianness)?;
301357
let _rss = read_u32(data, &mut cursor, endianness)?;
302-
let _iss_base = read_u32(data, &mut cursor, endianness)?;
358+
let iss_base = read_u32(data, &mut cursor, endianness)?;
303359
let _cb_ss = read_u32(data, &mut cursor, endianness)?;
304360
let isym_base = read_u32(data, &mut cursor, endianness)?;
305361
let csym = read_u32(data, &mut cursor, endianness)?;
@@ -317,7 +373,16 @@ impl FileDescriptor {
317373
let cb_line_offset = read_u32(data, &mut cursor, endianness)?;
318374
let cb_line = read_u32(data, &mut cursor, endianness)?;
319375

320-
Ok(FileDescriptor { adr, isym_base, csym, ipd_first, cpd, cb_line_offset, cb_line })
376+
Ok(FileDescriptor {
377+
adr,
378+
iss_base,
379+
isym_base,
380+
csym,
381+
ipd_first,
382+
cpd,
383+
cb_line_offset,
384+
cb_line,
385+
})
321386
}
322387
}
323388

@@ -354,6 +419,7 @@ impl ProcDescriptor {
354419

355420
#[derive(Clone, Copy)]
356421
struct SymbolEntry {
422+
iss: u32,
357423
value: u32,
358424
st: u8,
359425
index: u32,
@@ -364,14 +430,14 @@ fn parse_symbols(data: &[u8], endianness: Endianness) -> Result<Vec<SymbolEntry>
364430
let mut symbols = Vec::with_capacity(data.len() / SYMR_SIZE);
365431
let mut cursor = 0;
366432
while cursor + SYMR_SIZE <= data.len() {
367-
let _iss = read_u32(data, &mut cursor, endianness)?;
433+
let iss = read_u32(data, &mut cursor, endianness)?;
368434
let value = read_u32(data, &mut cursor, endianness)?;
369435
let bits = read_u32(data, &mut cursor, endianness)?;
370436
let (st, index) = match endianness {
371437
Endianness::Big => (((bits >> 26) & 0x3f) as u8, bits & 0x000f_ffff),
372438
Endianness::Little => (((bits & 0x3f) as u8), (bits >> 12) & 0x000f_ffff),
373439
};
374-
symbols.push(SymbolEntry { value, st, index });
440+
symbols.push(SymbolEntry { iss, value, st, index });
375441
}
376442
Ok(symbols)
377443
}

objdiff-core/tests/arch_mips.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,28 @@ fn mwcc_dwarf1_line_numbers_multiple_functions() {
102102
);
103103
}
104104
}
105+
106+
#[test]
107+
#[cfg(feature = "mips")]
108+
fn ee_gcc_mdebug_line_numbers() {
109+
let diff_config = diff::DiffObjConfig::default();
110+
let obj = obj::read::parse(
111+
include_object!("data/mips/ee_gcc_lines_example.o"),
112+
&diff_config,
113+
diff::DiffSide::Base,
114+
)
115+
.unwrap();
116+
117+
let text_section = obj.sections.iter().find(|s| s.name == ".text").unwrap();
118+
assert_eq!(text_section.line_info.get(&0), Some(&1));
119+
assert_eq!(text_section.line_info.get(&12), Some(&2));
120+
assert_eq!(text_section.line_info.get(&20), Some(&4));
121+
assert_eq!(text_section.line_info.get(&40), Some(&5));
122+
assert_eq!(text_section.line_info.get(&64), Some(&7));
123+
assert_eq!(text_section.line_info.get(&80), Some(&8));
124+
assert_eq!(text_section.line_info.get(&88), Some(&10));
125+
assert_eq!(text_section.line_info.get(&96), Some(&11));
126+
assert_eq!(text_section.line_info.get(&104), Some(&12));
127+
assert_eq!(text_section.line_info.get(&144), Some(&13));
128+
assert_eq!(text_section.line_info.len(), 10);
129+
}
3.27 KB
Binary file not shown.

0 commit comments

Comments
 (0)