@@ -11,6 +11,7 @@ package dap
1111import  (
1212	"bufio" 
1313	"bytes" 
14+ 	"encoding/base64" 
1415	"encoding/json" 
1516	"errors" 
1617	"fmt" 
@@ -104,6 +105,71 @@ type Server struct {
104105	sessionMu  sync.Mutex 
105106}
106107
108+ // memRef describe address and its size to stream data from 
109+ type  memRef  struct  {
110+ 	addr  uint64 
111+ 	size  int64 
112+ }
113+ 
114+ type  referencesCollection  struct  {
115+ 	mu    sync.Mutex 
116+ 	refs  map [string ]memRef 
117+ }
118+ 
119+ func  (r  * referencesCollection ) get (reference  string ) (memRef , bool ) {
120+ 	r .mu .Lock ()
121+ 	defer  r .mu .Unlock ()
122+ 
123+ 	ref , ok  :=  r .refs [reference ]
124+ 
125+ 	return  ref , ok 
126+ }
127+ 
128+ func  isAddressable (v  * proc.Variable ) bool  {
129+ 	if  v  ==  nil  ||  v .Unreadable  !=  nil  {
130+ 		return  false 
131+ 	}
132+ 
133+ 	switch  v .Kind  {
134+ 	case  reflect .Slice , reflect .String :
135+ 		return  true 
136+ 	}
137+ 
138+ 	return  false 
139+ }
140+ 
141+ func  (r  * referencesCollection ) put (v  * proc.Variable ) string  {
142+ 	if  ! isAddressable (v ) {
143+ 		return  "" 
144+ 	}
145+ 
146+ 	r .mu .Lock ()
147+ 	defer  r .mu .Unlock ()
148+ 
149+ 	if  r .refs  ==  nil  {
150+ 		r .refs  =  make (map [string ]memRef )
151+ 	}
152+ 
153+ 	addr  :=  v .Addr 
154+ 	if  v .Base  !=  0  {
155+ 		addr  =  v .Base 
156+ 	}
157+ 
158+ 	ref  :=  fmt .Sprintf ("0x%x" , addr )
159+ 	r .refs [ref ] =  memRef {addr : addr , size : v .Len }
160+ 
161+ 	return  ref 
162+ }
163+ 
164+ func  (r  * referencesCollection ) reset () {
165+ 	r .mu .Lock ()
166+ 	defer  r .mu .Unlock ()
167+ 
168+ 	if  len (r .refs ) >  0  {
169+ 		r .refs  =  make (map [string ]memRef )
170+ 	}
171+ }
172+ 
107173// Session is an abstraction for serving and shutting down 
108174// a DAP debug session with a pre-connected client. 
109175// TODO(polina): move this to a different file/package 
@@ -119,6 +185,8 @@ type Session struct {
119185	// Reset at every stop. 
120186	// See also comment for convertVariable. 
121187	variableHandles  * handlesMap [* fullyQualifiedVariable ]
188+ 	// referencesCollection track references map for DAP client 
189+ 	referencesCollection  referencesCollection 
122190	// args tracks special settings for handling debug session requests. 
123191	args  launchAttachArgs 
124192	// exceptionErr tracks the runtime error that last occurred. 
@@ -774,7 +842,7 @@ func (s *Session) handleRequest(request dap.Message) {
774842	case  * dap.LoadedSourcesRequest : // Optional (capability 'supportsLoadedSourcesRequest') 
775843		/*TODO*/  s .onLoadedSourcesRequest (request ) // Not yet implemented 
776844	case  * dap.ReadMemoryRequest : // Optional (capability 'supportsReadMemoryRequest') 
777- 		/*TODO*/   s .onReadMemoryRequest (request )  // Not yet implemented 
845+ 		s .onReadMemoryRequest (request )
778846	case  * dap.CancelRequest : // Optional (capability 'supportsCancelRequest') 
779847		/*TODO*/  s .onCancelRequest (request ) // Not yet implemented (does this make sense?) 
780848	case  * dap.ModulesRequest : // Optional (capability 'supportsModulesRequest') 
@@ -871,7 +939,7 @@ func (s *Session) onInitializeRequest(request *dap.InitializeRequest) {
871939	response .Body .SupportsRestartRequest  =  true 
872940	response .Body .SupportsSetExpression  =  false 
873941	response .Body .SupportsLoadedSourcesRequest  =  false 
874- 	response .Body .SupportsReadMemoryRequest  =  false 
942+ 	response .Body .SupportsReadMemoryRequest  =  true 
875943	response .Body .SupportsCancelRequest  =  false 
876944	response .Body .ExceptionBreakpointFilters  =  []dap.ExceptionBreakpointsFilter {
877945		{Filter : proc .UnrecoveredPanic , Label : "Unrecovered Panics" , Default : true },
@@ -2656,6 +2724,7 @@ func (s *Session) childrenToDAPVariables(v *fullyQualifiedVariable) []dap.Variab
26562724				VariablesReference : cvarref ,
26572725				IndexedVariables :   getIndexedVariableCount (c ),
26582726				NamedVariables :     getNamedVariableCount (c ),
2727+ 				MemoryReference :    s .referencesCollection .put (c ),
26592728			}
26602729		}
26612730	}
@@ -3355,10 +3424,92 @@ func (s *Session) onLoadedSourcesRequest(request *dap.LoadedSourcesRequest) {
33553424	s .sendNotYetImplementedErrorResponse (request .Request )
33563425}
33573426
3358- // onReadMemoryRequest sends a not-yet-implemented error response. 
3359- // Capability 'supportsReadMemoryRequest' is not set 'initialize' response. 
3427+ // onReadMemoryRequest handles DAP read memory requests 
33603428func  (s  * Session ) onReadMemoryRequest (request  * dap.ReadMemoryRequest ) {
3361- 	s .sendNotYetImplementedErrorResponse (request .Request )
3429+ 	args  :=  request .Arguments 
3430+ 
3431+ 	if  args .Count  <  0  {
3432+ 		s .sendErrorResponse (request .Request , UnableToReadMemory , "Unable to read memory" , "negative count" )
3433+ 		return 
3434+ 	}
3435+ 
3436+ 	ref , ok  :=  s .referencesCollection .get (args .MemoryReference )
3437+ 	if  ! ok  {
3438+ 		s .sendErrorResponse (request .Request , UnableToReadMemory , "Unable to read memory" , "unknown memoryReference" )
3439+ 		return 
3440+ 	}
3441+ 
3442+ 	if  args .Count  ==  0  {
3443+ 		s .send (makeReadMemoryResponse (request .Request , ref .addr , nil , 0 ))
3444+ 		return 
3445+ 	}
3446+ 
3447+ 	endReq  :=  int64 (args .Offset  +  args .Count )
3448+ 
3449+ 	startRead  :=  min (max (int64 (args .Offset ), 0 ), ref .size )
3450+ 	endRead  :=  min (max (endReq , 0 ), ref .size )
3451+ 
3452+ 	memAddr  :=  ref .addr  +  uint64 (startRead )
3453+ 
3454+ 	readCount  :=  endRead  -  startRead 
3455+ 	if  readCount  <=  0  {
3456+ 		unreadable  :=  max (args .Count , 0 )
3457+ 
3458+ 		s .send (makeReadMemoryResponse (request .Request , memAddr , nil , unreadable ))
3459+ 		return 
3460+ 	}
3461+ 
3462+ 	unreadable  :=  max (int64 (args .Count )- readCount , 0 )
3463+ 
3464+ 	data , n , err  :=  s .readTargetMemory (memAddr , readCount )
3465+ 	if  err  !=  nil  {
3466+ 		s .sendErrorResponse (request .Request , UnableToReadMemory , "Unable to read memory" , err .Error ())
3467+ 		return 
3468+ 	}
3469+ 
3470+ 	if  int64 (n ) <  readCount  {
3471+ 		unreadable  +=  readCount  -  int64 (n )
3472+ 	}
3473+ 
3474+ 	s .send (makeReadMemoryResponse (request .Request , memAddr , data , int (unreadable )))
3475+ }
3476+ 
3477+ func  (s  * Session ) readTargetMemory (addr  uint64 , count  int64 ) (data  []byte , n  int , err  error ) {
3478+ 	if  count  <=  0  {
3479+ 		return  nil , 0 , nil 
3480+ 	}
3481+ 
3482+ 	buf  :=  make ([]byte , count )
3483+ 
3484+ 	tgrp , unlock  :=  s .debugger .LockTargetGroup ()
3485+ 	defer  unlock ()
3486+ 
3487+ 	n , err  =  tgrp .Selected .Memory ().ReadMemory (buf , addr )
3488+ 	if  err  !=  nil  {
3489+ 		return  nil , 0 , err 
3490+ 	}
3491+ 
3492+ 	if  n  >  0  {
3493+ 		data  =  buf [:n ]
3494+ 	}
3495+ 
3496+ 	return  data , n , nil 
3497+ }
3498+ 
3499+ func  makeReadMemoryResponse (req  dap.Request , addr  uint64 , data  []byte , unreadable  int ) * dap.ReadMemoryResponse  {
3500+ 	var  response  string 
3501+ 	if  len (data ) >  0  {
3502+ 		response  =  base64 .StdEncoding .EncodeToString (data )
3503+ 	}
3504+ 
3505+ 	return  & dap.ReadMemoryResponse {
3506+ 		Response : * newResponse (req ),
3507+ 		Body : dap.ReadMemoryResponseBody {
3508+ 			Address :         fmt .Sprintf ("%#x" , addr ),
3509+ 			Data :            response ,
3510+ 			UnreadableBytes : unreadable ,
3511+ 		},
3512+ 	}
33623513}
33633514
33643515var  invalidInstruction  =  dap.DisassembledInstruction {
@@ -3814,6 +3965,7 @@ Use 'Continue' to resume the original step command.`
38143965func  (s  * Session ) resetHandlesForStoppedEvent () {
38153966	s .stackFrameHandles .reset ()
38163967	s .variableHandles .reset ()
3968+ 	s .referencesCollection .reset ()
38173969	s .exceptionErr  =  nil 
38183970}
38193971
0 commit comments