Skip to content

Commit 41c7ceb

Browse files
author
ci-bot
committed
debbug
1 parent 114b15e commit 41c7ceb

File tree

6 files changed

+410
-9
lines changed

6 files changed

+410
-9
lines changed

libs/remix-debug/src/debugger/debugger.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ export class Debugger {
7878
}
7979

8080
this.debugger.callTree.getValidSourceLocationFromVMTraceIndexFromCache(address, index, compilationResultForAddress.data.contracts).then(async (rawLocationAndOpcode) => {
81+
console.log(rawLocationAndOpcode)
8182
if (compilationResultForAddress && compilationResultForAddress.data) {
8283
const rawLocation = rawLocationAndOpcode.sourceLocation
8384
const stepDetail = rawLocationAndOpcode.stepDetail

libs/remix-debug/src/solidity-decoder/internalCallTree.ts

Lines changed: 156 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict'
22
import { AstWalker } from '@remix-project/remix-astwalker'
3+
import { nodesAtPositionForSourceLocation } from '../source/sourceMappingDecoder'
34
import { util } from '@remix-project/remix-lib'
45
import { SourceLocationTracker } from '../source/sourceLocationTracker'
56
import { EventManager } from '../eventManager'
@@ -50,6 +51,10 @@ export class InternalCallTree {
5051
[Key: number]: any
5152
}
5253

54+
codeManager: any
55+
scopesMapping: any
56+
processedFunctions: any
57+
5358
/**
5459
* constructor
5560
*
@@ -66,6 +71,7 @@ export class InternalCallTree {
6671
this.solidityProxy = solidityProxy
6772
this.traceManager = traceManager
6873
this.offsetToLineColumnConverter = offsetToLineColumnConverter
74+
this.codeManager = codeManager
6975
this.sourceLocationTracker = new SourceLocationTracker(codeManager, { debugWithGeneratedSources: opts.debugWithGeneratedSources })
7076
debuggerEvent.register('newTraceLoaded', async (trace) => {
7177
const time = Date.now()
@@ -131,6 +137,82 @@ export class InternalCallTree {
131137
this.constructorsStartExecution = {}
132138
this.pendingConstructor = null
133139
this.variables = {}
140+
141+
this.scopesMapping = {}
142+
this.processedFunctions = []
143+
}
144+
145+
/*
146+
async printSolArtefacts (vmtraceIndex) {
147+
const address = this.traceManager.getCurrentCalledAddressAt(vmtraceIndex)
148+
const contractObj = await this.solidityProxy.contractObjectAtAddress(address)
149+
const pc = this.traceManager.getCurrentPC(vmtraceIndex)
150+
const scope = this.findEntryByRange(pc, contractObj.contract.evm.deployedBytecode.functionDebugData)
151+
console.log(pc, scope, contractObj.contract.evm.deployedBytecode.functionDebugData)
152+
}*/
153+
154+
async getFunctionDebugData (vmtraceIndex, isCreation) {
155+
const address = this.traceManager.getCurrentCalledAddressAt(vmtraceIndex)
156+
const contractObj = await this.solidityProxy.contractObjectAtAddress(address)
157+
const debugData = isCreation ? contractObj.contract.evm.bytecode.functionDebugData : contractObj.contract.evm.deployedBytecode.functionDebugData
158+
const pc = this.traceManager.getCurrentPC(vmtraceIndex)
159+
const key = this.findEntryByRange(pc, debugData)
160+
return { key, value: debugData[key] }
161+
}
162+
163+
async printResolveLocals (vmtraceIndex) {
164+
const address = this.traceManager.getCurrentCalledAddressAt(vmtraceIndex)
165+
const sourceLocation = await this.extractValidSourceLocation(vmtraceIndex, address)
166+
// this doesn't yet handle generated sources
167+
const ast = await this.solidityProxy.ast(sourceLocation, null, address)
168+
const nodes = nodesAtPositionForSourceLocation('', sourceLocation, { ast })
169+
const node = nodes.reverse().find((node) => {
170+
return !!node.scope
171+
})
172+
if (!node) {
173+
console.log('node not found')
174+
return
175+
}
176+
const nodesbyScope = getAllItemByScope(this, ast, this.astWalker)
177+
const nodesForScope = nodesbyScope[node.scope]
178+
const locals = getVariableDeclarationForScope(nodesForScope)
179+
return {
180+
firstStep: 0,
181+
isCreation: false,
182+
gasCost: 0,
183+
lastStep: 0,
184+
locals
185+
}
186+
}
187+
188+
/**
189+
* Find the entry in mapping whose range contains the given number.
190+
* The range is defined between consecutive entryPoint values.
191+
*
192+
* @param {number} value - The number to search for
193+
* @param {Object} mapping - Mapping of entries with entryPoint values
194+
* @returns {string|null} The key of the matching entry, or null if not found
195+
*/
196+
findEntryByRange(value: number, mapping: { [key: string]: { entryPoint: number, id: number } }): string | null {
197+
// Convert mapping to sorted array of [key, entryPoint] pairs
198+
const entries = Object.entries(mapping)
199+
.map(([key, obj]) => ({ key, entryPoint: obj.entryPoint }))
200+
.sort((a, b) => a.entryPoint - b.entryPoint)
201+
202+
// Find the entry whose range contains the value
203+
for (let i = 0; i < entries.length; i++) {
204+
const currentEntry = entries[i]
205+
const nextEntry = entries[i + 1]
206+
207+
// Check if value is in range [currentEntry.entryPoint, nextEntry.entryPoint)
208+
if (value >= currentEntry.entryPoint) {
209+
if (!nextEntry || value < nextEntry.entryPoint) {
210+
return currentEntry.key
211+
}
212+
}
213+
}
214+
215+
return null
134216
}
135217

136218
/**
@@ -139,6 +221,9 @@ export class InternalCallTree {
139221
* @param {Int} vmtraceIndex - index on the vm trace
140222
*/
141223
findScope (vmtraceIndex) {
224+
225+
this.printResolveLocals(vmtraceIndex)
226+
142227
let scopeId = this.findScopeId(vmtraceIndex)
143228
if (scopeId !== '' && !scopeId) return null
144229
let scope = this.scopes[scopeId]
@@ -248,18 +333,33 @@ async function buildTree (tree, step, scopeId, isCreation, functionDefinition?,
248333
let previousValidSourceLocation = validSourceLocation || currentSourceLocation
249334
let compilationResult
250335
let currentAddress = ''
336+
let currentFunctionDebugData
251337
while (step < tree.traceManager.trace.length) {
252338
let sourceLocation
253339
let validSourceLocation
254340
let address
255-
341+
let isFunctionEntryPoint = false
342+
let functionDebugData
256343
try {
257344
address = tree.traceManager.getCurrentCalledAddressAt(step)
258345
sourceLocation = await tree.extractSourceLocation(step, address)
346+
functionDebugData = await tree.getFunctionDebugData(step, isCreation, currentFunctionDebugData)
347+
348+
if (functionDebugData && functionDebugData.value && functionDebugData.value.id && !tree.processedFunctions.includes(functionDebugData.value.id)) {
349+
currentFunctionDebugData = functionDebugData
350+
tree.processedFunctions.push(functionDebugData.value.id)
351+
console.log('found', functionDebugData.value.id)
352+
isFunctionEntryPoint = true
353+
}
354+
355+
if (step === 92 || step === 93) {
356+
console.log('start', sourceLocation)
357+
}
259358

260359
if (!includedSource(sourceLocation, currentSourceLocation)) {
261-
tree.reducedTrace.push(step)
360+
tree.reducedTrace.push(step)
262361
currentSourceLocation = sourceLocation
362+
// if (step === 92 || step === 93) console.log('not include', currentSourceLocation)
263363
}
264364
if (currentAddress !== address) {
265365
compilationResult = await tree.solidityProxy.compilationResult(address)
@@ -268,15 +368,21 @@ async function buildTree (tree, step, scopeId, isCreation, functionDefinition?,
268368
const amountOfSources = tree.sourceLocationTracker.getTotalAmountOfSources(address, compilationResult.data.contracts)
269369
if (tree.sourceLocationTracker.isInvalidSourceLocation(currentSourceLocation, amountOfSources)) { // file is -1 or greater than amount of sources
270370
validSourceLocation = previousValidSourceLocation
271-
} else
371+
} else {
272372
validSourceLocation = currentSourceLocation
373+
if (step === 92 || step === 93) console.log('valid', validSourceLocation, currentSourceLocation)
374+
}
273375

274376
} catch (e) {
275377
return { outStep: step, error: 'InternalCallTree - Error resolving source location. ' + step + ' ' + e }
276378
}
277379
if (!sourceLocation) {
278380
return { outStep: step, error: 'InternalCallTree - No source Location. ' + step }
279381
}
382+
383+
if (step === 92 || step === 93) {
384+
console.log('validSourceLocation', validSourceLocation, currentSourceLocation)
385+
}
280386
const stepDetail: StepDetail = tree.traceManager.trace[step]
281387
const nextStepDetail: StepDetail = tree.traceManager.trace[step + 1]
282388
if (stepDetail && nextStepDetail) {
@@ -300,7 +406,10 @@ async function buildTree (tree, step, scopeId, isCreation, functionDefinition?,
300406
}
301407
}
302408

409+
if (step === 92 || step === 93) console.log('bef offsetToLineColumn', validSourceLocation)
410+
303411
lineColumnPos = await tree.offsetToLineColumnConverter.offsetToLineColumn(validSourceLocation, validSourceLocation.file, sources, astSources)
412+
if (step === 92 || step === 93) console.log('lineColumnPos', lineColumnPos)
304413
if (!tree.gasCostPerLine[validSourceLocation.file]) tree.gasCostPerLine[validSourceLocation.file] = {}
305414
if (!tree.gasCostPerLine[validSourceLocation.file][lineColumnPos.start.line]) {
306415
tree.gasCostPerLine[validSourceLocation.file][lineColumnPos.start.line] = {
@@ -315,26 +424,42 @@ async function buildTree (tree, step, scopeId, isCreation, functionDefinition?,
315424
}
316425
}
317426

318-
tree.locationAndOpcodePerVMTraceIndex[step] = { sourceLocation, stepDetail, lineColumnPos, contractAddress: address }
427+
if (step === 92 || step === 93) console.log('set locationAndOpcodePerVMTraceIndex', validSourceLocation, lineColumnPos, stepDetail)
428+
tree.locationAndOpcodePerVMTraceIndex[step] = { sourceLocation: validSourceLocation, stepDetail, lineColumnPos, contractAddress: address }
319429
tree.scopes[scopeId].gasCost += stepDetail.gasCost
320430

321431
const contractObj = await tree.solidityProxy.contractObjectAtAddress(address)
322432
const generatedSources = getGeneratedSources(tree, scopeId, contractObj)
323-
const functionDefinition = await resolveFunctionDefinition(tree, sourceLocation, generatedSources, address)
433+
// const functionDefinition = await resolveFunctionDefinition(tree, sourceLocation, generatedSources, address)
324434

325435
const isInternalTxInstrn = isCallInstruction(stepDetail)
326436
const isCreateInstrn = isCreateInstruction(stepDetail)
327437
// we are checking if we are jumping in a new CALL or in an internal function
328438

329-
const constructorExecutionStarts = tree.pendingConstructorExecutionAt > -1 && tree.pendingConstructorExecutionAt < validSourceLocation.start
439+
const ast = Object.entries(compilationResult.data.sources).find((entry) => {
440+
return (entry[1] as any).id === validSourceLocation.file
441+
})
442+
443+
let functionDefinition
444+
tree.astWalker.walkFull((ast[1] as any).ast, (node) => {
445+
if (functionDebugData.value && node.id === functionDebugData.value.id) {
446+
functionDefinition = node
447+
}
448+
})
449+
// const nodesbyScope = getAllItemByScope(this, ast, this.astWalker)
450+
451+
// const nodesForScope = nodesbyScope[functionDebugData.value.id]
452+
//const locals = getVariableDeclarationForScope(nodesForScope)
453+
454+
const constructorExecutionStarts = functionDebugData.key === 'constructor_' + contractObj.name // tree.pendingConstructorExecutionAt > -1 && tree.pendingConstructorExecutionAt < validSourceLocation.start
330455
if (functionDefinition && functionDefinition.kind === 'constructor' && tree.pendingConstructorExecutionAt === -1 && !tree.constructorsStartExecution[functionDefinition.id]) {
331456
tree.pendingConstructorExecutionAt = validSourceLocation.start
332457
tree.pendingConstructorId = functionDefinition.id
333458
tree.pendingConstructor = functionDefinition
334459
// from now on we'll be waiting for a change in the source location which will mark the beginning of the constructor execution.
335460
// constructorsStartExecution allows to keep track on which constructor has already been executed.
336461
}
337-
const internalfunctionCall = functionDefinition && previousSourceLocation.jump === 'i'
462+
const internalfunctionCall = isFunctionEntryPoint
338463
if (constructorExecutionStarts || isInternalTxInstrn || internalfunctionCall) {
339464
try {
340465
const newScopeId = scopeId === '' ? subScope.toString() : scopeId + '.' + subScope
@@ -525,3 +650,27 @@ function addParams (parameterList, tree, scopeId, states, contractObj, sourceLoc
525650
}
526651
return params
527652
}
653+
654+
function getAllItemByScope (tree, ast, astWalker) {
655+
if (Object.keys(tree.scopesMapping).length > 0) return tree.scopesMapping
656+
astWalker.walkFull(ast, (node) => {
657+
if (node.scope) {
658+
if (!tree.scopesMapping[node.scope]) tree.scopesMapping[node.scope] = []
659+
tree.scopesMapping[node.scope].push(node)
660+
}
661+
})
662+
return tree.scopesMapping
663+
}
664+
665+
function getVariableDeclarationForScope (nodes) {
666+
const ret = []
667+
nodes.filter((node) => {
668+
if (node.nodeType === 'VariableDeclaration' || node.nodeType === 'YulVariableDeclaration') {
669+
ret.push(node)
670+
}
671+
const hasChild = node.initialValue && (node.nodeType === 'VariableDeclarationStatement' || node.nodeType === 'YulVariableDeclarationStatement')
672+
if (hasChild) ret.push(node.declarations)
673+
})
674+
return ret
675+
}
676+

0 commit comments

Comments
 (0)