@@ -305,17 +305,153 @@ private void DeleteRangeFromCache(DisassemblyBlock block)
305305 }
306306 }
307307
308+ private class DisasmAddressRange
309+ {
310+ public ulong StartAddress ;
311+ public ulong EndAddress ;
312+ Dictionary < ulong , DisasmInstruction > AddressToInstruction ;
313+
314+ public DisasmAddressRange ( DisasmInstruction instruction )
315+ {
316+ StartAddress = instruction . Addr ;
317+ EndAddress = instruction . Addr ;
318+ AddressToInstruction = new Dictionary < ulong , DisasmInstruction > ( )
319+ {
320+ { instruction . Addr , instruction }
321+ } ;
322+ }
323+
324+ public void UpdateEndAddress ( DisasmInstruction instruction )
325+ {
326+ EndAddress = instruction . Addr ;
327+ AddressToInstruction . Add ( instruction . Addr , instruction ) ;
328+ }
329+
330+ public void MapSourceToInstructions ( DebuggedProcess process , TupleValue [ ] src_and_asm_lines )
331+ {
332+ /* Example response
333+ * [
334+ * {
335+ * line="15",
336+ * file="main.cpp",
337+ * fullname="/home/cpp/main.cpp",
338+ * line_asm_insn=[
339+ * {
340+ * address="0x0000000008001485",
341+ * func-name="main(int, char**)",
342+ * offset="316",
343+ * opcodes="83 bd 4c ff ff ff 00",
344+ * inst="cmpl $0x0,-0xb4(%rbp)"
345+ * },
346+ * {
347+ * address="0x000000000800148c",
348+ * func-name="main(int, char**)",
349+ * offset="323",
350+ * opcodes="75 07",
351+ * inst="jne 0x8001495 <main(int, char**)+332>"
352+ * }
353+ * ]
354+ * }
355+ * ]
356+ */
357+ foreach ( TupleValue src_and_asm_line in src_and_asm_lines )
358+ {
359+ uint line = src_and_asm_line . FindUint ( "line" ) ;
360+ string file = process . GetMappedFileFromTuple ( src_and_asm_line ) ;
361+ ValueListValue line_asm_instructions = src_and_asm_line . Find < ValueListValue > ( "line_asm_insn" ) ;
362+ foreach ( ResultValue line_asm_insn in line_asm_instructions . Content )
363+ {
364+ ulong address = line_asm_insn . FindAddr ( "address" ) ;
365+ AddressToInstruction [ address ] . File = file ;
366+ AddressToInstruction [ address ] . Line = line ;
367+ }
368+ }
369+ }
370+ }
371+
308372 // this is inefficient so we try and grab everything in one gulp
309373 internal static async Task < DisasmInstruction [ ] > Disassemble ( DebuggedProcess process , ulong startAddr , ulong endAddr )
310374 {
375+ // Due to GDB not returning source information when requesting outside of the range of user code.
376+ // We first get disassembly with opcodes, then map each Symbol to an address range and attempt to retrieve source information per Symbol.
377+
378+ // Mode 2 - disassembly with raw opcodes
311379 string cmd = "-data-disassemble -s " + EngineUtils . AsAddr ( startAddr , process . Is64BitArch ) + " -e " + EngineUtils . AsAddr ( endAddr , process . Is64BitArch ) + " -- 2" ;
312380 Results results = await process . CmdAsync ( cmd , ResultClass . None ) ;
313381 if ( results . ResultClass != ResultClass . done )
314382 {
315383 return null ;
316384 }
317385
318- return DecodeDisassemblyInstructions ( results . Find < ValueListValue > ( "asm_insns" ) . AsArray < TupleValue > ( ) ) ;
386+ DisasmInstruction [ ] instructions = DecodeDisassemblyInstructions ( results . Find < ValueListValue > ( "asm_insns" ) . AsArray < TupleValue > ( ) ) ;
387+
388+ if ( instructions != null && instructions . Length != 0 )
389+ {
390+ // Map 'Symbol' (Function Name) to Address Range
391+ Dictionary < string , DisasmAddressRange > funcToAddressRange = new Dictionary < string , DisasmAddressRange > ( ) ;
392+ for ( int i = 0 ; i < instructions . Length ; i ++ )
393+ {
394+ string functionName = instructions [ i ] . Symbol ;
395+ if ( funcToAddressRange . ContainsKey ( functionName ) )
396+ {
397+ // Update the end address with this current instruction.
398+ funcToAddressRange [ functionName ] . UpdateEndAddress ( instructions [ i ] ) ;
399+ }
400+ else
401+ {
402+ // Insert new function to keep track of.
403+ funcToAddressRange . Add ( functionName , new DisasmAddressRange ( instructions [ i ] ) ) ;
404+ }
405+
406+ // endAddr will not show up in instructions, so make the last instruction we get to get the range til the end.
407+ if ( i == instructions . Length - 1 )
408+ {
409+ funcToAddressRange [ functionName ] . EndAddress = endAddr ;
410+ }
411+ }
412+
413+ foreach ( string functionName in funcToAddressRange . Keys )
414+ {
415+ DisasmAddressRange range = funcToAddressRange [ functionName ] ;
416+
417+ // Mode 5 - mixed source and disassembly with raw opcodes
418+ cmd = "-data-disassemble -s " + EngineUtils . AsAddr ( range . StartAddress , process . Is64BitArch ) + " -e " + EngineUtils . AsAddr ( range . EndAddress , process . Is64BitArch ) + " -- 5" ;
419+ results = await process . CmdAsync ( cmd , ResultClass . None ) ;
420+ if ( results . ResultClass != ResultClass . done )
421+ {
422+ return null ;
423+ }
424+ try
425+ {
426+ /* Example response
427+ * asm_insns=[
428+ * src_and_asm_line={
429+ * line="15",
430+ * file="main.cpp",
431+ * fullname="/home/cpp/main.cpp",
432+ * line_asm_insn=[ ... ]
433+ * }
434+ * ]
435+ */
436+ ResultListValue asm_insns = results . Find < ResultListValue > ( "asm_insns" ) ;
437+ if ( asm_insns != null )
438+ {
439+ TupleValue [ ] values = asm_insns . FindAll < TupleValue > ( "src_and_asm_line" ) ;
440+ if ( values != null )
441+ {
442+ range . MapSourceToInstructions ( process , values ) ;
443+ }
444+ }
445+ }
446+ catch
447+ {
448+ // asm_insns can be ValueListValue if it does not contain source information.
449+ }
450+ }
451+ }
452+
453+
454+ return instructions ;
319455 }
320456
321457 // this is inefficient so we try and grab everything in one gulp
0 commit comments