But until your debuger has ALL that internal debugger has (including save/restore support and work with param treee) + will suit for all Bochs' usages (x86-64 support, smp support) - it will not become default replace for internal debugger.
I already have full 64 bit compatibility. By the end of this week, I will have
better SMP and param_tree support than the current internal debugger has.
So the question is whether I can figure out how the internal debugger is preventing me from having
really good SMP support. Because right now, if I bypass the internal debugger and call cpu_loop(0) from "the wrong thread", then cpu_loop crashes.
As far as save/restore goes: there is no documentation on this, so it will be hard to do. How does it work? What do I need to do to support it? What needs to be saved and restored?
You write the debugger trying to follow Bochs coding guidelines
I think I have. The only thing I didn't do was convert tabs to spaces. When I have a more fully-tested version, that I really intend to submit as a bochs patch, I can write a quickie routine to do the tab conversion on the files.
I want to make currrent debugger compatible with this inetrface and working.
Your suggestions?
The problem is: the current internal debugger interface is single-threaded, and is not thread-safe.
The sim also assumes that it is single-threaded.
There are places where it tests SIM->is_sim_thread() -- this will need to be eliminated. The CPU code is probably already thread-safe, except that it currently expects to ONLY be called from the single debugger/sim thread.
Probably the easiest and best way to "patch" this (so it continues to work with everything), is to use a registered callback inside the bx_dbg_user_input_loop() function. That way, I can change it from accessing the current sleep loop, and have it call MY input function synchronously, when it wants input.
This would also serve as a flag that the simulation was at a break.
I will write an example, and see if I can get you and WindowsNT to agree to it.
Errors I have seen so far in the bochs code:
bewing wrote: ...and the "if" is backwards, so the watchpoints don't work correctly anyway.
This I can't understand. As far as I know the watchpoints work correctly everywhere.
The watchpoint "if" currently says:
Code: Select all
if (write_watchpoint[i] <= phy && write_watchpoint[i] + len > phy) {
It
should say:
Code: Select all
if (write_watchpoint[i] >= phy && write_watchpoint[i] < phy + len ) {
To see that the watchpoints don't work correcty, try setting one to a byte address in the middle of a dword, and then accessing the entire dword. Your watchpoint won't fire.
ALSO -- I mentioned this to you once before (but I said the problem wrong):
Currently, the A20ADDR macro says:
Code: Select all
#if BX_SUPPORT_A20
# define A20ADDR(x) (bx_phy_address(x) & bx_pc_system.a20_mask)
#else
# define A20ADDR(x) (bx_phy_address(x))
#endif
But the bx_phy_address is supposed to be a
cast -- so it
should have more parentheses and say:
Code: Select all
#if BX_SUPPORT_A20
# define A20ADDR(x) ((bx_phy_address)(x) & bx_pc_system.a20_mask)
#else
# define A20ADDR(x) ((bx_phy_address)(x))
#endif
My compiler is picky enough to get a fatal error over this A20ADDR macro.
Also if you hav some suggestions for making it more efficient - I am open for ideas.
This applies to the watchpoint list, and also to the way breakpoints are handled in CPU.
If you have a
sorted breakpoint list, you can make a loop that looks like this:
Code: Select all
bx_address h = CurrentAddress;
int j= BreakCount;
while (--j >= 0) // loop over all breakpoints
{
// brk list is sorted -- if the value goes too low, end the loop
if (BrkLAddr[j] < h)
j = 0; // force the loop to end if it goes too far -- no breakpoint match
else if (BrkLAddr[j] == h){
j = 0;
break! // hit a breakpoint
}
}
Notes:
1) Counting the loop down, so it tests on zero, is always more efficient -- if possible.
2) Storing the breakpoint list in a separate array, rather than inside a structure, is always more efficient.
3) The point about this loop is that on average it only has to test HALF of the breakpoints before it knows that there is no match.
4) It is even possible to start j at a better value than BreakCount. You can start the loop by testing if BrkLAddr[BreakCount/2] >= h -- if it is, then you start j there. Then, on average, you only have to test a
quarter of the breakpoints before you know there is no match.
5) Most current compilers are smart enough to understand that you are doing the same comparison twice, so GOOD compiled assembly code would say something like:
Code: Select all
mov ecx, [BreakCount]
.brklp:
dec ecx
jl short .done
mov eax, [h]
cmp [BrkLAddr + ecx*4], eax
jge short .tste
xor ecx, ecx ; kill the loop
jmp short .brklp
.tste: jne short .brklp
break! ; hit a breakpoint
.done:
Unfortunately, MY compiler is so stupid that I have to force it, with something like:
Code: Select all
int j= BreakCount;
while (--j >= 0) // loop over all breakpoints
{
// brk list is sorted -- if the value goes too low, end the loop
register breakpt_address i = BrkLAddr[j] - h; // precalculate the comparison
if (i < 0)
j = 0; // force the loop to end if it goes too far -- no breakpoint match
else if (i == 0){
j = 0;
break! // hit a breakpoint
}
}
And if I had lots of time, I'd completely rewrite your param tree interface for you. If you put everything into the param tree, the way it is built right now, bochs is going to be one of the slowest emulators ever seen.