diff --git a/ghidra-extension/src/main/java/libghidra/host/runtime/DecompilerRuntime.java b/ghidra-extension/src/main/java/libghidra/host/runtime/DecompilerRuntime.java index eb3cdc9..4779676 100644 --- a/ghidra-extension/src/main/java/libghidra/host/runtime/DecompilerRuntime.java +++ b/ghidra-extension/src/main/java/libghidra/host/runtime/DecompilerRuntime.java @@ -61,11 +61,11 @@ public DecompilerContract.ListDecompilationsResponse listDecompilations( try { long defaultStart = program.getMinAddress().getOffset(); long startOffset = request != null ? request.rangeStart() : defaultStart; - long endOffset = resolveRangeEnd(request != null ? request.rangeEnd() : 0); - if (startOffset <= 0) { + long endOffset = request != null ? request.rangeEnd() : -1L; + if (startOffset == 0) { startOffset = defaultStart; } - if (endOffset < startOffset) { + if (Long.compareUnsigned(endOffset, startOffset) < 0) { return new DecompilerContract.ListDecompilationsResponse(List.of()); } @@ -88,10 +88,10 @@ public DecompilerContract.ListDecompilationsResponse listDecompilations( continue; } long address = function.getEntryPoint().getOffset(); - if (address < startOffset) { + if (Long.compareUnsigned(address, startOffset) < 0) { continue; } - if (address > endOffset) { + if (Long.compareUnsigned(address, endOffset) > 0) { break; } if (seen++ < offset) { diff --git a/ghidra-extension/src/main/java/libghidra/host/runtime/FunctionsRuntime.java b/ghidra-extension/src/main/java/libghidra/host/runtime/FunctionsRuntime.java index 5061522..1d7c8c1 100644 --- a/ghidra-extension/src/main/java/libghidra/host/runtime/FunctionsRuntime.java +++ b/ghidra-extension/src/main/java/libghidra/host/runtime/FunctionsRuntime.java @@ -75,11 +75,11 @@ public FunctionsContract.ListFunctionsResponse listFunctions( try { long defaultStart = program.getMinAddress().getOffset(); long startOffset = request != null ? request.rangeStart() : defaultStart; - long endOffset = resolveRangeEnd(request != null ? request.rangeEnd() : 0); - if (startOffset <= 0) { + long endOffset = request != null ? request.rangeEnd() : -1L; + if (startOffset == 0) { startOffset = defaultStart; } - if (endOffset < startOffset) { + if (Long.compareUnsigned(endOffset, startOffset) < 0) { return new FunctionsContract.ListFunctionsResponse(List.of()); } @@ -97,10 +97,10 @@ public FunctionsContract.ListFunctionsResponse listFunctions( continue; } long address = function.getEntryPoint().getOffset(); - if (address < startOffset) { + if (Long.compareUnsigned(address, startOffset) < 0) { continue; } - if (address > endOffset) { + if (Long.compareUnsigned(address, endOffset) > 0) { break; } if (seen++ < offset) { @@ -187,8 +187,8 @@ public FunctionsContract.ListBasicBlocksResponse listBasicBlocks( try { long defaultStart = program.getMinAddress().getOffset(); long startOff = request != null ? request.rangeStart() : defaultStart; - long endOff = resolveRangeEnd(request != null ? request.rangeEnd() : 0); - if (startOff <= 0) { + long endOff = request != null ? request.rangeEnd() : -1L; + if (startOff == 0) { startOff = defaultStart; } int offset = request != null ? Math.max(0, request.offset()) : 0; @@ -202,10 +202,10 @@ public FunctionsContract.ListBasicBlocksResponse listBasicBlocks( while (funcIter.hasNext() && rows.size() < limit) { Function func = funcIter.next(); long funcEntry = func.getEntryPoint().getOffset(); - if (funcEntry < startOff) { + if (Long.compareUnsigned(funcEntry, startOff) < 0) { continue; } - if (funcEntry > endOff) { + if (Long.compareUnsigned(funcEntry, endOff) > 0) { break; } AddressSetView body = func.getBody(); @@ -244,8 +244,8 @@ public FunctionsContract.ListCFGEdgesResponse listCFGEdges( try { long defaultStart = program.getMinAddress().getOffset(); long startOff = request != null ? request.rangeStart() : defaultStart; - long endOff = resolveRangeEnd(request != null ? request.rangeEnd() : 0); - if (startOff <= 0) { + long endOff = request != null ? request.rangeEnd() : -1L; + if (startOff == 0) { startOff = defaultStart; } int offset = request != null ? Math.max(0, request.offset()) : 0; @@ -259,10 +259,10 @@ public FunctionsContract.ListCFGEdgesResponse listCFGEdges( while (funcIter.hasNext() && rows.size() < limit) { Function func = funcIter.next(); long funcEntry = func.getEntryPoint().getOffset(); - if (funcEntry < startOff) { + if (Long.compareUnsigned(funcEntry, startOff) < 0) { continue; } - if (funcEntry > endOff) { + if (Long.compareUnsigned(funcEntry, endOff) > 0) { break; } AddressSetView body = func.getBody(); @@ -450,8 +450,8 @@ public FunctionsContract.ListSwitchTablesResponse listSwitchTables( try { long defaultStart = program.getMinAddress().getOffset(); long startOff = request != null ? request.rangeStart() : defaultStart; - long endOff = resolveRangeEnd(request != null ? request.rangeEnd() : 0); - if (startOff <= 0) { startOff = defaultStart; } + long endOff = request != null ? request.rangeEnd() : -1L; + if (startOff == 0) { startOff = defaultStart; } int pOffset = request != null ? Math.max(0, request.offset()) : 0; int limit = request != null && request.limit() > 0 ? request.limit() : 4096; @@ -467,8 +467,8 @@ public FunctionsContract.ListSwitchTablesResponse listSwitchTables( while (funcIter.hasNext() && rows.size() < limit) { Function func = funcIter.next(); long funcEntry = func.getEntryPoint().getOffset(); - if (funcEntry < startOff) { continue; } - if (funcEntry > endOff) { break; } + if (Long.compareUnsigned(funcEntry, startOff) < 0) { continue; } + if (Long.compareUnsigned(funcEntry, endOff) > 0) { break; } if (func.isExternal()) { continue; } DecompileResults results = @@ -527,8 +527,8 @@ public FunctionsContract.ListDominatorsResponse listDominators( try { long defaultStart = program.getMinAddress().getOffset(); long startOff = request != null ? request.rangeStart() : defaultStart; - long endOff = resolveRangeEnd(request != null ? request.rangeEnd() : 0); - if (startOff <= 0) { startOff = defaultStart; } + long endOff = request != null ? request.rangeEnd() : -1L; + if (startOff == 0) { startOff = defaultStart; } int pOffset = request != null ? Math.max(0, request.offset()) : 0; int limit = request != null && request.limit() > 0 ? request.limit() : 4096; @@ -540,8 +540,8 @@ public FunctionsContract.ListDominatorsResponse listDominators( while (funcIter.hasNext() && rows.size() < limit) { Function func = funcIter.next(); long funcEntry = func.getEntryPoint().getOffset(); - if (funcEntry < startOff) { continue; } - if (funcEntry > endOff) { break; } + if (Long.compareUnsigned(funcEntry, startOff) < 0) { continue; } + if (Long.compareUnsigned(funcEntry, endOff) > 0) { break; } List funcDoms = buildDominatorRecords(func, blockModel, false); @@ -572,8 +572,8 @@ public FunctionsContract.ListPostDominatorsResponse listPostDominators( try { long defaultStart = program.getMinAddress().getOffset(); long startOff = request != null ? request.rangeStart() : defaultStart; - long endOff = resolveRangeEnd(request != null ? request.rangeEnd() : 0); - if (startOff <= 0) { startOff = defaultStart; } + long endOff = request != null ? request.rangeEnd() : -1L; + if (startOff == 0) { startOff = defaultStart; } int pOffset = request != null ? Math.max(0, request.offset()) : 0; int limit = request != null && request.limit() > 0 ? request.limit() : 4096; @@ -585,8 +585,8 @@ public FunctionsContract.ListPostDominatorsResponse listPostDominators( while (funcIter.hasNext() && rows.size() < limit) { Function func = funcIter.next(); long funcEntry = func.getEntryPoint().getOffset(); - if (funcEntry < startOff) { continue; } - if (funcEntry > endOff) { break; } + if (Long.compareUnsigned(funcEntry, startOff) < 0) { continue; } + if (Long.compareUnsigned(funcEntry, endOff) > 0) { break; } List reversedDoms = buildDominatorRecords(func, blockModel, true); @@ -619,8 +619,8 @@ public FunctionsContract.ListLoopsResponse listLoops( try { long defaultStart = program.getMinAddress().getOffset(); long startOff = request != null ? request.rangeStart() : defaultStart; - long endOff = resolveRangeEnd(request != null ? request.rangeEnd() : 0); - if (startOff <= 0) { startOff = defaultStart; } + long endOff = request != null ? request.rangeEnd() : -1L; + if (startOff == 0) { startOff = defaultStart; } int pOffset = request != null ? Math.max(0, request.offset()) : 0; int limit = request != null && request.limit() > 0 ? request.limit() : 4096; @@ -636,8 +636,8 @@ public FunctionsContract.ListLoopsResponse listLoops( while (funcIter.hasNext() && rows.size() < limit) { Function func = funcIter.next(); long funcEntry = func.getEntryPoint().getOffset(); - if (funcEntry < startOff) { continue; } - if (funcEntry > endOff) { break; } + if (Long.compareUnsigned(funcEntry, startOff) < 0) { continue; } + if (Long.compareUnsigned(funcEntry, endOff) > 0) { break; } if (func.isExternal()) { continue; } DecompileResults results = diff --git a/ghidra-extension/src/main/java/libghidra/host/runtime/ListingRuntime.java b/ghidra-extension/src/main/java/libghidra/host/runtime/ListingRuntime.java index c6d045d..27ebc60 100644 --- a/ghidra-extension/src/main/java/libghidra/host/runtime/ListingRuntime.java +++ b/ghidra-extension/src/main/java/libghidra/host/runtime/ListingRuntime.java @@ -70,11 +70,11 @@ public ListingContract.ListInstructionsResponse listInstructions( try { long defaultStart = program.getMinAddress().getOffset(); long startOffset = request != null ? request.rangeStart() : defaultStart; - long endOffset = resolveRangeEnd(request != null ? request.rangeEnd() : 0); - if (startOffset <= 0) { + long endOffset = request != null ? request.rangeEnd() : -1L; + if (startOffset == 0) { startOffset = defaultStart; } - if (endOffset < startOffset) { + if (Long.compareUnsigned(endOffset, startOffset) < 0) { return new ListingContract.ListInstructionsResponse(List.of()); } @@ -88,10 +88,10 @@ public ListingContract.ListInstructionsResponse listInstructions( while (it.hasNext()) { Instruction instruction = it.next(); long address = instruction.getAddress().getOffset(); - if (address < startOffset) { + if (Long.compareUnsigned(address, startOffset) < 0) { continue; } - if (address > endOffset) { + if (Long.compareUnsigned(address, endOffset) > 0) { break; } if (seen++ < offset) { @@ -120,11 +120,11 @@ public ListingContract.GetCommentsResponse getComments(ListingContract.GetCommen try { long defaultStart = program.getMinAddress().getOffset(); long startOffset = request != null ? request.rangeStart() : defaultStart; - long endOffset = resolveRangeEnd(request != null ? request.rangeEnd() : 0); - if (startOffset <= 0) { + long endOffset = request != null ? request.rangeEnd() : -1L; + if (startOffset == 0) { startOffset = defaultStart; } - if (endOffset < startOffset) { + if (Long.compareUnsigned(endOffset, startOffset) < 0) { return new ListingContract.GetCommentsResponse(List.of()); } @@ -159,9 +159,15 @@ public ListingContract.GetCommentsResponse getComments(ListingContract.GetCommen } // Range path: iterate code units with early termination. + // Clamp the end to the start space's max (an unbounded request carries + // endOffset = -1/INT64_MAX) and intersect with loaded memory, so we never + // walk undefined code units across the empty gap up to the top of the + // address space — that turns a "list all comments" query into a hang. Address start = toAddress(program, startOffset); - Address end = toAddress(program, endOffset); - AddressSet set = new AddressSet(start, end); + long spaceMax = start.getAddressSpace().getMaxAddress().getOffset(); + long clampedEnd = Long.compareUnsigned(endOffset, spaceMax) > 0 ? spaceMax : endOffset; + Address end = toAddress(program, clampedEnd); + AddressSet set = new AddressSet(start, end).intersect(program.getMemory()); CodeUnitIterator it = listing.getCodeUnits(set, true); int pageOffset = request != null ? Math.max(0, request.offset()) : 0; int limit = request != null && request.limit() > 0 ? request.limit() : 512; @@ -372,11 +378,11 @@ public ListingContract.ListDataItemsResponse listDataItems( try { long defaultStart = program.getMinAddress().getOffset(); long startOffset = request != null ? request.rangeStart() : defaultStart; - long endOffset = resolveRangeEnd(request != null ? request.rangeEnd() : 0); - if (startOffset <= 0) { + long endOffset = request != null ? request.rangeEnd() : -1L; + if (startOffset == 0) { startOffset = defaultStart; } - if (endOffset < startOffset) { + if (Long.compareUnsigned(endOffset, startOffset) < 0) { return new ListingContract.ListDataItemsResponse(List.of()); } int offset = request != null ? Math.max(0, request.offset()) : 0; @@ -393,7 +399,7 @@ public ListingContract.ListDataItemsResponse listDataItems( } Address address = data.getAddress(); long addressOffset = address.getOffset(); - if (addressOffset < startOffset || addressOffset > endOffset) { + if (Long.compareUnsigned(addressOffset, startOffset) < 0 || Long.compareUnsigned(addressOffset, endOffset) > 0) { continue; } long endAddress = data.getMaxAddress() != null @@ -439,11 +445,11 @@ public ListingContract.ListBookmarksResponse listBookmarks( try { long defaultStart = program.getMinAddress().getOffset(); long startOffset = request != null ? request.rangeStart() : defaultStart; - long endOffset = resolveRangeEnd(request != null ? request.rangeEnd() : 0); - if (startOffset <= 0) { + long endOffset = request != null ? request.rangeEnd() : -1L; + if (startOffset == 0) { startOffset = defaultStart; } - if (endOffset < startOffset) { + if (Long.compareUnsigned(endOffset, startOffset) < 0) { return new ListingContract.ListBookmarksResponse(List.of()); } @@ -465,7 +471,7 @@ public ListingContract.ListBookmarksResponse listBookmarks( continue; } long address = bookmark.getAddress().getOffset(); - if (address < startOffset || address > endOffset) { + if (Long.compareUnsigned(address, startOffset) < 0 || Long.compareUnsigned(address, endOffset) > 0) { continue; } if (!typeFilter.isEmpty() && !typeFilter.equals(bookmark.getTypeString())) { @@ -582,11 +588,11 @@ public ListingContract.ListBreakpointsResponse listBreakpoints( try { long defaultStart = program.getMinAddress().getOffset(); long startOffset = request != null ? request.rangeStart() : defaultStart; - long endOffset = resolveRangeEnd(request != null ? request.rangeEnd() : 0); - if (startOffset <= 0) { + long endOffset = request != null ? request.rangeEnd() : -1L; + if (startOffset == 0) { startOffset = defaultStart; } - if (endOffset < startOffset) { + if (Long.compareUnsigned(endOffset, startOffset) < 0) { return new ListingContract.ListBreakpointsResponse(List.of()); } @@ -605,7 +611,7 @@ public ListingContract.ListBreakpointsResponse listBreakpoints( for (Bookmark bookmark : BreakpointBookmarkStore.all(manager)) { BreakpointBookmarkStore.BreakpointRecord row = BreakpointBookmarkStore.fromBookmark(bookmark); - if (row.address < startOffset || row.address > endOffset) { + if (Long.compareUnsigned(row.address, startOffset) < 0 || Long.compareUnsigned(row.address, endOffset) > 0) { continue; } if (!kindFilter.isEmpty() && @@ -830,8 +836,8 @@ public ListingContract.ListDefinedStringsResponse listDefinedStrings( try { long defaultStart = program.getMinAddress().getOffset(); long startOff = request != null ? request.rangeStart() : defaultStart; - long endOff = resolveRangeEnd(request != null ? request.rangeEnd() : 0); - if (startOff <= 0) { + long endOff = request != null ? request.rangeEnd() : -1L; + if (startOff == 0) { startOff = defaultStart; } int offset = request != null ? Math.max(0, request.offset()) : 0; @@ -843,10 +849,10 @@ public ListingContract.ListDefinedStringsResponse listDefinedStrings( program, dt -> dt instanceof ghidra.program.model.data.AbstractStringDataType)) { long addr = data.getAddress().getOffset(); - if (addr < startOff) { + if (Long.compareUnsigned(addr, startOff) < 0) { continue; } - if (addr > endOff) { + if (Long.compareUnsigned(addr, endOff) > 0) { break; } if (seen++ < offset) { diff --git a/ghidra-extension/src/main/java/libghidra/host/runtime/RuntimeSupport.java b/ghidra-extension/src/main/java/libghidra/host/runtime/RuntimeSupport.java index ae29c3d..270817c 100644 --- a/ghidra-extension/src/main/java/libghidra/host/runtime/RuntimeSupport.java +++ b/ghidra-extension/src/main/java/libghidra/host/runtime/RuntimeSupport.java @@ -70,21 +70,6 @@ protected static Address toAddress(Program program, long offset) { } } - /** - * Normalize a "list" RPC's range-end offset, treating a non-positive value as unbounded. - * - *

The C++ client encodes an unbounded upper bound as the protobuf {@code uint64} - * {@code UINT64_MAX}, which is decoded here into a signed Java {@code long} as {@code -1}. - * Earlier code fell back to {@code program.getMaxAddress().getOffset()} for any - * non-positive end; for programs whose maximum address lives in a low-offset space (an - * EXTERNAL block, or file-backed "OTHER" sections at offset 0) that collapsed the scan - * window and made range-filtered tables return no rows. Treating it as - * {@link Long#MAX_VALUE} keeps the scan unbounded. See ghidrasql #2/#3/#6. - */ - protected static long resolveRangeEnd(long requestedEnd) { - return requestedEnd <= 0 ? Long.MAX_VALUE : requestedEnd; - } - protected static void writeBytesForceWritable(Program program, Address address, byte[] data) throws MemoryAccessException { Memory memory = program.getMemory(); diff --git a/ghidra-extension/src/main/java/libghidra/host/runtime/SymbolsRuntime.java b/ghidra-extension/src/main/java/libghidra/host/runtime/SymbolsRuntime.java index 608f287..b47ad72 100644 --- a/ghidra-extension/src/main/java/libghidra/host/runtime/SymbolsRuntime.java +++ b/ghidra-extension/src/main/java/libghidra/host/runtime/SymbolsRuntime.java @@ -48,11 +48,11 @@ public SymbolsContract.ListSymbolsResponse listSymbols(SymbolsContract.ListSymbo try { long defaultStart = program.getMinAddress().getOffset(); long startOffset = request != null ? request.rangeStart() : defaultStart; - long endOffset = resolveRangeEnd(request != null ? request.rangeEnd() : 0); - if (startOffset <= 0) { + long endOffset = request != null ? request.rangeEnd() : -1L; + if (startOffset == 0) { startOffset = defaultStart; } - if (endOffset < startOffset) { + if (Long.compareUnsigned(endOffset, startOffset) < 0) { return new SymbolsContract.ListSymbolsResponse(List.of()); } @@ -70,10 +70,10 @@ public SymbolsContract.ListSymbolsResponse listSymbols(SymbolsContract.ListSymbo continue; } long address = symbol.getAddress().getOffset(); - if (address < startOffset) { + if (Long.compareUnsigned(address, startOffset) < 0) { continue; } - if (address > endOffset) { + if (Long.compareUnsigned(address, endOffset) > 0) { break; } if (seen++ < offset) { diff --git a/ghidra-extension/src/main/java/libghidra/host/runtime/TypesRuntime.java b/ghidra-extension/src/main/java/libghidra/host/runtime/TypesRuntime.java index 09eac38..e0fe556 100644 --- a/ghidra-extension/src/main/java/libghidra/host/runtime/TypesRuntime.java +++ b/ghidra-extension/src/main/java/libghidra/host/runtime/TypesRuntime.java @@ -350,11 +350,11 @@ public TypesContract.ListFunctionSignaturesResponse listFunctionSignatures( try { long defaultStart = program.getMinAddress().getOffset(); long startOffset = request != null ? request.rangeStart() : defaultStart; - long endOffset = resolveRangeEnd(request != null ? request.rangeEnd() : 0); - if (startOffset <= 0) { + long endOffset = request != null ? request.rangeEnd() : -1L; + if (startOffset == 0) { startOffset = defaultStart; } - if (endOffset < startOffset) { + if (Long.compareUnsigned(endOffset, startOffset) < 0) { return new TypesContract.ListFunctionSignaturesResponse(List.of()); } @@ -372,10 +372,10 @@ public TypesContract.ListFunctionSignaturesResponse listFunctionSignatures( continue; } long address = function.getEntryPoint().getOffset(); - if (address < startOffset) { + if (Long.compareUnsigned(address, startOffset) < 0) { continue; } - if (address > endOffset) { + if (Long.compareUnsigned(address, endOffset) > 0) { break; } if (seen++ < offset) { diff --git a/ghidra-extension/src/main/java/libghidra/host/runtime/XrefsRuntime.java b/ghidra-extension/src/main/java/libghidra/host/runtime/XrefsRuntime.java index 4a29cb3..4b03013 100644 --- a/ghidra-extension/src/main/java/libghidra/host/runtime/XrefsRuntime.java +++ b/ghidra-extension/src/main/java/libghidra/host/runtime/XrefsRuntime.java @@ -25,11 +25,11 @@ public XrefsContract.ListXrefsResponse listXrefs(XrefsContract.ListXrefsRequest try { long defaultStart = program.getMinAddress().getOffset(); long startOffset = request != null ? request.rangeStart() : defaultStart; - long endOffset = resolveRangeEnd(request != null ? request.rangeEnd() : 0); - if (startOffset <= 0) { + long endOffset = request != null ? request.rangeEnd() : -1L; + if (startOffset == 0) { startOffset = defaultStart; } - if (endOffset < startOffset) { + if (Long.compareUnsigned(endOffset, startOffset) < 0) { return new XrefsContract.ListXrefsResponse(List.of()); } @@ -44,10 +44,10 @@ public XrefsContract.ListXrefsResponse listXrefs(XrefsContract.ListXrefsRequest while (fromIterator.hasNext()) { Address fromAddress = fromIterator.next(); long fromOffset = fromAddress.getOffset(); - if (fromOffset < startOffset) { + if (Long.compareUnsigned(fromOffset, startOffset) < 0) { continue; } - if (fromOffset > endOffset) { + if (Long.compareUnsigned(fromOffset, endOffset) > 0) { break; } Reference[] refs = referenceManager.getReferencesFrom(fromAddress); diff --git a/python/examples/pagination.py b/python/examples/pagination.py index b638edf..36f9edb 100644 --- a/python/examples/pagination.py +++ b/python/examples/pagination.py @@ -46,7 +46,7 @@ def main() -> int: print("=== fetch_all: all functions ===\n") all_funcs = fetch_all( lambda limit, offset: client.list_functions( - range_start=0, range_end=2**64 - 1, limit=limit, offset=offset + range_start=0, range_end=2**63 - 1, limit=limit, offset=offset ).functions ) print(f"Total functions: {len(all_funcs)}") @@ -61,7 +61,7 @@ def main() -> int: offset = 0 while page_num < 5: items = client.list_symbols( - range_start=0, range_end=2**64 - 1, limit=25, offset=offset + range_start=0, range_end=2**63 - 1, limit=25, offset=offset ).symbols if not items: break @@ -78,7 +78,7 @@ def main() -> int: print("\n=== fetch_all: all function signatures ===\n") all_sigs = fetch_all( lambda limit, offset: client.list_function_signatures( - range_start=0, range_end=2**64 - 1, limit=limit, offset=offset + range_start=0, range_end=2**63 - 1, limit=limit, offset=offset ).signatures ) print(f"Total signatures: {len(all_sigs)}")