@@ -4,9 +4,10 @@ use std::collections::HashMap;
44use std:: fmt;
55use std:: iter;
66
7+ use lazycell:: LazyCell ;
78use symbolic_common:: { Arch , CodeId , DebugId } ;
89use symbolic_ppdb:: EmbeddedSource ;
9- use symbolic_ppdb:: { FormatError , PortablePdb } ;
10+ use symbolic_ppdb:: { Document , FormatError , PortablePdb } ;
1011
1112use crate :: base:: * ;
1213
@@ -141,24 +142,44 @@ impl fmt::Debug for PortablePdbObject<'_> {
141142/// A debug session for a Portable PDB object.
142143pub struct PortablePdbDebugSession < ' data > {
143144 ppdb : PortablePdb < ' data > ,
144- sources : HashMap < String , EmbeddedSource < ' data > > ,
145+ sources : LazyCell < HashMap < String , PPDBSource < ' data > > > ,
146+ }
147+
148+ #[ derive( Debug , Clone ) ]
149+ enum PPDBSource < ' data > {
150+ Embedded ( EmbeddedSource < ' data > ) ,
151+ Link ( Document ) ,
145152}
146153
147154impl < ' data > PortablePdbDebugSession < ' data > {
148155 fn new ( ppdb : & ' _ PortablePdb < ' data > ) -> Result < Self , FormatError > {
149- let mut sources: HashMap < String , EmbeddedSource < ' data > > = HashMap :: new ( ) ;
150- for source in ppdb. get_embedded_sources ( ) ? {
151- match source {
152- Ok ( source) => sources. insert ( source. get_path ( ) . into ( ) , source) ,
153- Err ( e) => return Err ( e) ,
154- } ;
155- }
156156 Ok ( PortablePdbDebugSession {
157157 ppdb : ppdb. clone ( ) ,
158- sources,
158+ sources : LazyCell :: new ( ) ,
159159 } )
160160 }
161161
162+ fn init_sources ( & self ) -> HashMap < String , PPDBSource < ' data > > {
163+ let count = self . ppdb . get_documents_count ( ) . unwrap_or ( 0 ) ;
164+ let mut result = HashMap :: with_capacity ( count) ;
165+
166+ if let Ok ( iter) = self . ppdb . get_embedded_sources ( ) {
167+ for source in iter. flatten ( ) {
168+ result. insert ( source. get_path ( ) . to_string ( ) , PPDBSource :: Embedded ( source) ) ;
169+ }
170+ } ;
171+
172+ for i in 1 ..count + 1 {
173+ if let Ok ( doc) = self . ppdb . get_document ( i) {
174+ if !result. contains_key ( & doc. name ) {
175+ result. insert ( doc. name . clone ( ) , PPDBSource :: Link ( doc) ) ;
176+ }
177+ }
178+ }
179+
180+ result
181+ }
182+
162183 /// Returns an iterator over all functions in this debug file.
163184 pub fn functions ( & self ) -> PortablePdbFunctionIterator < ' _ > {
164185 iter:: empty ( )
@@ -169,15 +190,17 @@ impl<'data> PortablePdbDebugSession<'data> {
169190 PortablePdbFileIterator :: new ( & self . ppdb )
170191 }
171192
172- /// Looks up a file's source contents by its full canonicalized path.
173- ///
174- /// The given path must be canonicalized.
175- pub fn source_by_path ( & self , path : & str ) -> Result < Option < Cow < ' _ , str > > , FormatError > {
176- match self . sources . get ( path) {
193+ /// See [DebugSession::source_by_path] for more information.
194+ pub fn source_by_path ( & self , path : & str ) -> Result < Option < SourceCode < ' _ > > , FormatError > {
195+ let sources = self . sources . borrow_with ( || self . init_sources ( ) ) ;
196+ match sources. get ( path) {
177197 None => Ok ( None ) ,
178- Some ( source) => source
198+ Some ( PPDBSource :: Embedded ( source) ) => source
179199 . get_contents ( )
180- . map ( |bytes| Some ( from_utf8_cow_lossy ( & bytes) ) ) ,
200+ . map ( |bytes| Some ( SourceCode :: Content ( from_utf8_cow_lossy ( & bytes) ) ) ) ,
201+ Some ( PPDBSource :: Link ( document) ) => {
202+ Ok ( self . ppdb . get_source_link ( document) . map ( SourceCode :: Url ) )
203+ }
181204 }
182205 }
183206}
@@ -195,7 +218,7 @@ impl<'data, 'session> DebugSession<'session> for PortablePdbDebugSession<'data>
195218 self . files ( )
196219 }
197220
198- fn source_by_path ( & self , path : & str ) -> Result < Option < Cow < ' _ , str > > , Self :: Error > {
221+ fn source_by_path ( & self , path : & str ) -> Result < Option < SourceCode < ' _ > > , Self :: Error > {
199222 self . source_by_path ( path)
200223 }
201224}
0 commit comments