@@ -19,14 +19,17 @@ use std::path::Path;
1919use std:: path:: PathBuf ;
2020
2121use crate :: elf:: ElfParser ;
22+ use crate :: elf:: BUILD_ID_DEBUG_DIR ;
23+ use crate :: elf:: BUILD_ID_DEBUG_EXTENSION ;
2224use crate :: error:: IntoError as _;
2325use crate :: util:: align_up_usize;
2426use crate :: util:: bytes_to_os_str;
2527use crate :: util:: ReadRaw as _;
28+ use crate :: BuildId ;
2629use crate :: Result ;
2730
28-
2931enum State {
32+ BuildId ,
3033 FixedDir {
3134 idx : usize ,
3235 } ,
@@ -47,6 +50,8 @@ pub(crate) struct DebugFileIter<'path> {
4750 canonical_linker : Option < & ' path Path > ,
4851 /// The debug link target file.
4952 linkee : & ' path OsStr ,
53+ /// The build id of the binary.
54+ build_id : Option < BuildId < ' path > > ,
5055 /// The iteration state.
5156 state : State ,
5257}
@@ -56,12 +61,14 @@ impl<'path> DebugFileIter<'path> {
5661 fixed_dirs : & ' path [ PathBuf ] ,
5762 canonical_linker : Option < & ' path Path > ,
5863 linkee : & ' path OsStr ,
64+ build_id : Option < BuildId < ' path > > ,
5965 ) -> Self {
6066 Self {
6167 fixed_dirs,
6268 canonical_linker,
6369 linkee,
64- state : State :: FixedDir { idx : 0 } ,
70+ build_id,
71+ state : State :: BuildId ,
6572 }
6673 }
6774
@@ -84,6 +91,38 @@ impl Iterator for DebugFileIter<'_> {
8491
8592 fn next ( & mut self ) -> Option < Self :: Item > {
8693 match & mut self . state {
94+ State :: BuildId => {
95+ self . state = State :: FixedDir { idx : 0 } ;
96+
97+ let Some ( build_id) = self . build_id . as_ref ( ) else {
98+ return self . next ( )
99+ } ;
100+
101+ // Technically we can check just 2 bytes with the code below,
102+ // but anything that short is probably bogus and worth skipping.
103+ if build_id. len ( ) < 8 {
104+ return self . next ( ) ;
105+ }
106+
107+ let mut path = PathBuf :: from ( BUILD_ID_DEBUG_DIR ) ;
108+
109+ let mut build_id_iter = build_id. iter ( ) ;
110+
111+ if let Some ( first) = build_id_iter. next ( ) {
112+ path. push ( format ! ( "{first:02x}" ) ) ;
113+ } else {
114+ return self . next ( ) ;
115+ }
116+
117+ path. push ( format ! (
118+ "{}.{BUILD_ID_DEBUG_EXTENSION}" ,
119+ build_id_iter
120+ . map( |byte| format!( "{byte:02x}" ) )
121+ . collect:: <String >( )
122+ ) ) ;
123+
124+ self . report_or_next ( path)
125+ }
87126 State :: FixedDir { idx } => {
88127 if let Some ( dir) = self . fixed_dirs . get ( * idx) {
89128 * idx += 1 ;
@@ -309,17 +348,27 @@ mod tests {
309348 #[ test]
310349 fn debug_file_iteration ( ) {
311350 let fixed_dirs = [ PathBuf :: from ( "/usr/lib/debug" ) ] ;
312- let files = DebugFileIter :: new ( fixed_dirs. as_slice ( ) , None , OsStr :: new ( "libc.so.debug" ) )
313- . collect :: < Vec < _ > > ( ) ;
351+ let files = DebugFileIter :: new (
352+ fixed_dirs. as_slice ( ) ,
353+ None ,
354+ OsStr :: new ( "libc.so.debug" ) ,
355+ None ,
356+ )
357+ . collect :: < Vec < _ > > ( ) ;
314358 let expected = vec ! [ PathBuf :: from( "/usr/lib/debug/libc.so.debug" ) ] ;
315359 assert_eq ! ( files, expected) ;
316360
317361 let fixed_dirs = DEFAULT_DEBUG_DIRS
318362 . iter ( )
319363 . map ( PathBuf :: from)
320364 . collect :: < Vec < _ > > ( ) ;
321- let files = DebugFileIter :: new ( fixed_dirs. as_slice ( ) , None , OsStr :: new ( "libc.so.debug" ) )
322- . collect :: < Vec < _ > > ( ) ;
365+ let files = DebugFileIter :: new (
366+ fixed_dirs. as_slice ( ) ,
367+ None ,
368+ OsStr :: new ( "libc.so.debug" ) ,
369+ None ,
370+ )
371+ . collect :: < Vec < _ > > ( ) ;
323372 let expected = vec ! [
324373 PathBuf :: from( "/usr/lib/debug/libc.so.debug" ) ,
325374 PathBuf :: from( "/lib/debug/libc.so.debug" ) ,
@@ -331,6 +380,7 @@ mod tests {
331380 fixed_dirs. as_slice ( ) ,
332381 Some ( Path :: new ( "/usr/lib64/libc.so" ) ) ,
333382 OsStr :: new ( "libc.so.debug" ) ,
383+ Some ( BuildId :: Owned ( vec ! [ 0xbe , 0xef , 0xbe , 0xef ] ) ) , // too short
334384 )
335385 . collect :: < Vec < _ > > ( ) ;
336386
@@ -350,10 +400,14 @@ mod tests {
350400 fixed_dirs. as_slice ( ) ,
351401 Some ( Path :: new ( "/usr/lib64/libc.so" ) ) ,
352402 OsStr :: new ( "libc.so.debug" ) ,
403+ Some ( BuildId :: Owned ( vec ! [
404+ 0xbe , 0xef , 0xbe , 0xef , 0xfe , 0xed , 0xba , 0xbe ,
405+ ] ) ) ,
353406 )
354407 . collect :: < Vec < _ > > ( ) ;
355408
356409 let expected = vec ! [
410+ PathBuf :: from( "/usr/lib/debug/.build-id/be/efbeeffeedbabe.debug" ) ,
357411 PathBuf :: from( "/usr/lib/debug/libc.so.debug" ) ,
358412 PathBuf :: from( "/lib/debug/libc.so.debug" ) ,
359413 PathBuf :: from( "/usr/lib64/libc.so.debug" ) ,
@@ -371,8 +425,16 @@ mod tests {
371425 fixed_dirs. as_slice ( ) ,
372426 Some ( Path :: new ( "/usr/lib64/libc.so" ) ) ,
373427 OsStr :: new ( "libc.so" ) ,
428+ Some ( BuildId :: Owned ( vec ! [
429+ 0xbe , 0xef , 0xbe , 0xef , 0xfe , 0xed , 0xba , 0xbe ,
430+ ] ) ) ,
374431 )
375432 . collect :: < Vec < _ > > ( ) ;
376- assert_eq ! ( files, Vec :: <PathBuf >:: new( ) ) ;
433+ assert_eq ! (
434+ files,
435+ vec![ PathBuf :: from(
436+ "/usr/lib/debug/.build-id/be/efbeeffeedbabe.debug"
437+ ) ]
438+ ) ;
377439 }
378440}
0 commit comments