Closed lolwheel closed 2 years ago
OK, so except for the "...caused exception processing attributesChanged", all of these are pretty normal errors for a remote target. I suspect we can still ignore that one, though. As an aside, I'd take GDB's advice and use the "file" command, if you have the image on disk. The errors about "Not supported on this target" and "Could not list regions" are typical for remote targets. We use "info proc mappings" to obtain a process memory map, but remote targets don't support it, so it just falls back to one or two entries covering the entire address space. The other behaviors are all symptoms of not having a "recording." We're actively working on relaxing this requirement, but it seems Ghidra was unable to identify the remote platform. It's pretty straightforward to fix. We'll try remedies in this order:
To get started, expand the "Environment" node in your "Objects" tree. Note the values for os and arch (debugger should be "gdb"). You can also type show os
and show arch
into the "Interpreter" window, if you prefer.
1) If arch is not what you expect, then disconnect and reconnect Ghidra to gdb, set the arch, then reconnect to the remote. If that works, then we're all done. Just remember to set your arch each time or add it to your .gdbinit
. Sometimes setting it to something more specific will help Ghidra, even if it appears to have no affect on GDB.
2) If that didn't work, then in the "Objects" pane, select Inferior 1, right-click and select "Record." It should present a langauge/platform selection box. Choose the one that best matches your platform and hit OK. If you have a choice between "ARM/GDB for..." and "Default GDB for...," choose the former. If that worked, then you might consider proceeding to step 3 to make it automatic in the future. If it didn't work, then let us know.
3) Edit Ghidra's ARM.ldefs file (should be Ghidra/Processors/ARM/data/languages/ARM.ldefs
). In there you should see external_name
attributes which provide a mapping from Ghidra's languages to GNU/GDB's arch names. Presumably there is no entry which exactly matches what show arch
reports for your target. Find the Ghidra language that worked from step 2 and add the appropriate external_name
element to it, restart Ghidra, then retry connecting to your target.
Hey Dan, thanks for all the hand-holding.
none
, arch is arm
and endianness is little
in the "Environment" node so no surprises here.
Offset must be between 0x0 and 0xffffffff, got 0x7ffffffffffffffe instead!
ghidra.program.model.address.AddressOutOfBoundsException: Offset must be between 0x0 and 0xffffffff, got 0x7ffffffffffffffe instead!
at ghidra.program.model.address.AbstractAddressSpace.makeValidOffset(AbstractAddressSpace.java:626)
at ghidra.program.model.address.GenericAddressSpace.makeValidOffset(GenericAddressSpace.java:21)
at ghidra.program.model.address.GenericAddress.<init>(GenericAddress.java:55)
at ghidra.program.model.address.GenericAddressSpace.getAddress(GenericAddressSpace.java:88)
at ghidra.app.plugin.core.debug.mapping.DefaultDebuggerMemoryMapper.toSameNamedSpace(DefaultDebuggerMemoryMapper.java:41)
at ghidra.app.plugin.core.debug.mapping.DefaultDebuggerMemoryMapper.targetToTrace(DefaultDebuggerMemoryMapper.java:66)
at ghidra.app.plugin.core.debug.mapping.DefaultDebuggerMemoryMapper.targetToTrace(DefaultDebuggerMemoryMapper.java:72)
at ghidra.app.plugin.core.debug.service.model.RecorderSimpleMemory.getAccessibleMemory(RecorderSimpleMemory.java:97)
at ghidra.app.plugin.core.debug.service.model.DefaultProcessRecorder.getAccessibleProcessMemory(DefaultProcessRecorder.java:65)
at ghidra.app.plugin.core.debug.service.model.DefaultTraceRecorder.getAccessibleProcessMemory(DefaultTraceRecorder.java:528)
at ghidra.app.plugin.core.debug.gui.action.VisibleROOnceAutoReadMemorySpec.readMemory(VisibleROOnceAutoReadMemorySpec.java:61)
at ghidra.app.plugin.core.debug.gui.action.DebuggerReadsMemoryTrait.doAutoRead(DebuggerReadsMemoryTrait.java:253)
at ghidra.app.plugin.core.debug.gui.action.DebuggerReadsMemoryTrait.goToCoordinates(DebuggerReadsMemoryTrait.java:248)
at ghidra.app.plugin.core.debug.gui.memory.DebuggerMemoryBytesProvider.goToCoordinates(DebuggerMemoryBytesProvider.java:312)
at ghidra.app.plugin.core.debug.gui.memory.DebuggerMemoryBytesProvider.coordinatesActivated(DebuggerMemoryBytesProvider.java:319)
at ghidra.app.plugin.core.debug.gui.memory.DebuggerMemoryBytesPlugin.lambda$processEvent$1(DebuggerMemoryBytesPlugin.java:172)
at ghidra.app.plugin.core.debug.gui.memory.DebuggerMemoryBytesPlugin.allProviders(DebuggerMemoryBytesPlugin.java:161)
at ghidra.app.plugin.core.debug.gui.memory.DebuggerMemoryBytesPlugin.processEvent(DebuggerMemoryBytesPlugin.java:172)
at ghidra.framework.plugintool.Plugin.eventSent(Plugin.java:329)
at ghidra.framework.plugintool.mgr.EventManager.sendEvents(EventManager.java:286)
at ghidra.framework.plugintool.mgr.EventManager.lambda$new$3(EventManager.java:49)
at ghidra.util.Swing.doRun(Swing.java:292)
at ghidra.util.Swing.runNow(Swing.java:208)
at ghidra.util.Swing.runNow(Swing.java:163)
at ghidra.framework.plugintool.mgr.EventManager.fireEvent(EventManager.java:216)
at ghidra.framework.plugintool.PluginTool.firePluginEvent(PluginTool.java:475)
at ghidra.framework.plugintool.Plugin.firePluginEvent(Plugin.java:481)
at ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin.fireLocationEvent(DebuggerTraceManagerServicePlugin.java:700)
at ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin.lambda$prepareViewAndFireEvent$18(DebuggerTraceManagerServicePlugin.java:695)
at java.base/java.util.concurrent.CompletableFuture$UniAccept.tryFire(CompletableFuture.java:718)
at java.base/java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:482)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:741)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Build Date: 2022-May-19 0956 EDT Ghidra Version: 10.1.4 Java Home: /usr/lib/jvm/java-17-openjdk-amd64 JVM Version: Private Build 17.0.1 OS: Linux 5.11.0-49-generic amd64
The address seems 64 bit while the platform I picked is 32 bit so there's that. Attaching screenshot too:
![image](https://user-images.githubusercontent.com/96507237/173767297-4ce488f7-73f7-42a4-a550-e2221b656314.png)
Thanks once again.
Oiy, OK. Not sure if you can dismiss that dialog long enough to check the "Regions" tab in the bottom left? My guess is it contains a defaultLow and defaultHigh entry, covering 64-bits of space rather than just the 32 supported by your platform? If that's the case and you have a dev environment, you might try patching GdbModelTargetProcessMemory.java at or about line 76. Just hardcode one GdbMemoryMapping(0, 1L<<32, 1L<<32, "default"). In any case, I'll see about a proper fix.
The "Regions" tab is empty:
OK so I think I got it working. What did the trick is the instruction that I found here: https://gist.github.com/aldelaro5/d532b21b5e2ec48d5f78e81846c1c1b7
I added following lines to the .gdbinit
that I source from Ghidra:
define info proc mappings
echo 0x0 0xFFFFFFFF 0x100000000 0x0 mem \n
end
After this, I also had to do what you suggested in the first comment, which is to hit "Record" button and picked the correct architecture which finally made Ghidra happy.
I would lie if I fully understood what's going on here but my impression is that Ghidra is polling GDB for the memory layout it has from the device. I was wondering if it's possible to feed GDB the memory layout defined in the Ghidra project itself as a fallback, if GDB doesn't have it? The rationale for this is that most of the Ghidra tutorials for embedded reverse engineering suggest using the SVD loader plugin which ends up producing a very accurate memory map of the system.
Anyways, thank you once again Dan, Cheers!
EDIT: Oh I also figured out the external_name
issue. arm
seems to be too generic. When I changed set arch arm
to set arch armv7
, I don't have to even hit the "Record" button and pick the architecture there. Awesome!
Glad you got it working!
As far as feeding the memory map from Ghidra back to GDB, that's not built-in. We aim for one interface to model several debuggers, so we have few, if any, special provisions for GDB. In general, the communication pattern is: commands go from Ghidra to the debugger, data is sent from debugger to Ghidra. That said, you may be able to write a GDB-specific script to accomplish your goal.
info proc mappings
. The example .gdbinit you gave actually does this, faking out the full 32-bit address space. You would generate an echo
line for each ALLOCED block in the memory map. Just write this out to a script file.Step 1 can get complicated depending on how well you know Ghidra's scripting API. Use getMemoryBlocks()
and then filter for those in "ram" and whose name is not EXTERNAL
. You may need some additional tweaking, but that should get you only the real ALLOCED ones.
Step 2 is definitely more complicated, because we don't have "script conveniences" for the debugger, yet. Use state.getTool().getService(DebuggerModelService.class)
to get the "model service". This manages the debugger's connections. Use modelService.getCurrentModel()
to get the current connection. Assuming it's GDB, you can use (TargetInterpreter) model.getModelRoot()
. This will get the "session" object and cast it to an interpreter. The cast doesn't work in general, but it works for GDB. That interface has execute(String)
and executeCapture(String)
, which you can use to run arbitrary GDB CLI commands. Due to a bug, it can't be used for multi-line commands, which is why you have to write the temporary script file. Remember to call .get()
on the CompletableFuture, so that you can handle any errors.
Thanks for the tips and debugging Dan.
In retrospect, it would be nice if Gghidra logged at least some errors when its core expectations such as defined "Recorder" or proc mapping
are absent. I am very lucky to have someone as helpful as you explaining this to me, I bet this discouraged others from using this amazing tool more.
In the meantime I bumped into another issue: My Dynamic and Static listings aren't synchronized. I looked at https://github.com/NationalSecurityAgency/ghidra/issues/2578 where you suggested that the culprit might be unmapped module. The thing is, there are no modules present or known to gdb
when connected to OpenOCD.
I tried looking up potential commands that Ghidra might be issuing to gdb
to spoof the output but couldn't find anything useful after 15 mins of Googling so I'm back for help.
We actually have some changes in the pipe to mitigate and at least warn users when the "launch" process fails or only completes partially. It's still awaiting review, though. It addresses "record failures" as well as "mapping failures". So that should be coming soon.
As far mapping/syncing in your case, I think the only option is to "map identically". Since gdb produces neither a memory map nor a module list, it has no idea what program to sync with in the static listing. From the "Modules" window's drop-down menu, select "Map Identically." This assumes your current program is loaded in the current target without relocation. It'll sync the two listings by exact address.
If there is relocation, you can add the mapping entry manually: Window -> Debugger -> Static Mappings. There's an "Add" button in the toolbar.
Thanks Dan, this solved it all. I'm going to edit my first comment in the issue so that others stumbling into the same issues find the answers easily.
I'm not sure if I should just close the issue at this point or you want to do it after addressing the https://github.com/NationalSecurityAgency/ghidra/issues/4345#issuecomment-1156457726. I'll leave this up to you.
Yes, please leave it open. We'll close it once we decide what to do re/ the GdbModelTargetProcessMemory.java
issue. Thanks!
EDIT: For those who bump into the same issue and don't want to scan through the comments, follow these steps to fix it. Add following lines to a text file and source it from Ghidra GDB window. You have to source them from a file as running
define info proc mappings
requires interactive input which Ghidra GDB console doesn't support yet:The last line points to the default OpenOCD gdb port. Tweak if you need to. The last step to link the Dynamic and Static listings is to open the Modules window and hit the static mapping button on it. Clicking it will start tracking the current execution point in the Listings and Decompiler window. That's it.
END EDIT
When trying to connect to the local OpenOCD instance via IN-VM GDB local debugger, a couple things happen: The GDB window shows several errors right after I connect to the OpenOCD via
target ext :3333
:The "Debug Console" pane immediately shows following errors:
The "Objects" pane does show the stack and registers. Every other window stays in its default state - all of them are empty and the Listings pane in scrolled to the entry point. Hitting "Step into" or "Step Over" buttons makes more of the same errors appear in both the GDB logs and the "Debug Console"
To Reproduce
gdb
fromgcc-arm-none-eabi-10.3-2021.10
packagetar ext :3333
Expected behavior No errors, functional Stepping, generally other windows behaving as if the target is connected to.
Screenshots
Attachments If applicable, please attach any files that caused problems or log files generated by the software.
Environment (please complete the following information):
Additional context Using the
gdb
in console works totally fine, with the following.gdbinit
and using the same exactgdb
binary that I'm pointing Ghidra to, I'm able to step through the assembly without any errors: