On Monday, 26 November 2018 at 10:42:02 UTC, Michelle Long wrote:
On Tuesday, 20 November 2018 at 15:11:56 UTC, Stefan Koch wrote:
On Sunday, 4 November 2018 at 21:17:32 UTC, Michelle Long wrote:
On Sunday, 4 November 2018 at 08:27:34 UTC, Rainer Schuetze wrote:
[...]


Is it then possible to simply split a line internally to handle it?

[...]

Debug information is mapped to machine-code on a source line by source line basis.

Therefore it's indeed nontrivial to do this.


Why would that be non-trivial?

semantically there is nothing different between

statement; statement;


Theoretically nothing's stopping a debugger from setting a breakpoint in between those 2 statements. Because when those statements are compiled to machine code that structure doesn't exist anymore. There's no whitespace in machine code nor statements separated by a delimiter.

Consider this:

A)
10| int x = 0; int y = 0; // this is line number 10 in the source file
11| writeln(x, y);

B)
10| int x = 0, y = 0; // this is line number 10 in the source file
11| writeln(x, y);

C)
10| int x = 0; // this is line number 10 in the source file
11| int y = 0;
12| writeln(x, y);

this would be translated to something like this (and is highly dependent on the architecture):

0x00230| xor accumulator, accumulator
0x00231| move to-address-of-var-x, value-of-accumulator
0x00233| move to-address-of-var-y, value-of-accumulator
0x00235| ...
^
| this is the address of the machine code in memory

all of these assignments would compile to the same 3 machine instructions. (This is not quite how it actually works but just to show the concept. Depending on the architecture it might not be possible to write to an address directly, and it would have to be loaded into an address register to which the value would then be moved. Also consider stack, variable alignment, machine instructions might need to be aligned and padded with NOPs, etc., etc.)

So what happens when you set a breakpoint on line 10 in your debugger ?

The debugger will rewrite your code in RAM and overwrite the instruction on address 0x00230 with an INT3, like so:

0x00230| INT3
0x00232| move to-address-of-var-x, value-of-accumulator
0x00234| move to-address-of-var-y, value-of-accumulator
0x00235| ...

The INT3 is a one-byte instruction (and applies to the x86 architecture) intended to be used by debuggers in order to interrupt the flow of a running program.

The important part here is: one-byte instruction. Which means it can be used to overwrite any machine instruction.

Once the CPU executes the INT3 instruction, the execution stops and you regain control of your program in the debugger.

Now it depends on how you proceed.

I) You continue execution, e.g. by pressing F5 -> The debugger restores the original opcode (xor accumulator, accumulator) to address 0x00230, and transfers control back to the CPU which continues to execute instruction at address 0x00231, 0x00232, etc.


II) You single step, e.g. by pressing F8.

Case A) and B) behave in the same way, the debugger would write the INT3 instruction to 0x00235, restore 0x00230 and resume. And halt again, executing code at 0x00235.

Case C) behaves similarly but would write INT3 to 0x00233, then next step to 0x00235, etc.

So, because INT3 is a one byte instruction, theoretically, debuggers could set a breakpoint in between the same one statement, like after pushing the function parameters on the stack, but before making the actual call.

0x00235| push x
0x00237| push y
0x00239| call writeln | <- by overwriting the call with INT3

But if all this is possible in theory why can't you break on your 'statment2;' ?

The answer is granularity. Line number ganularity to be more specific.

In order for the debugger to know where statement 1; is the compiler must generate debug information. Which is a map that maps the address of a machine instruction to a line in - oh wait - what actually is a line ?

Technically there are no lines in your source code either. It's simply a stream of characters and lines are a convention, a formatting hint, for your editor.
This convention differs even between different OSs.
On Posix the convention is a line feed (ASCII code 10).
On Windows it is a carriage return (ASCII code 13) followed immediately by a line feed.

You can see this concept when you open a text file produced in a Posix environment in Windows Notepad. (although, I believe, a recent Windows 10 Notepad understands both conventions.)

So, back to debug info.
The compiler maps the address of the instruction to the offset of that CR/LF offset in your source code file. (It might be a little bit more complicated than that with indirections and stuff so someone more knowledgeable in that domain might want to weigh in)

And since the CR/LF is the granularity of the debug info you can't get better resolution for your breakpoints in your debugger.

Now if you wanted to set a breakpoint at any statement in a line, or inside for(...;...;...) loops, etc. you would need a) a compiler that can produce this kind of debug info, and b) a debugger which can take advantage of it.

So technically you would need 2 different pieces of software to work together which probably are made by completely different groups people, who would have to reach consensus - and that's why it's non-trivial.
  • Can't set BP in m... Michelle Long via Digitalmars-d-debugger
    • Re: Can't se... Rainer Schuetze via Digitalmars-d-debugger
      • Re: Can'... Michelle Long via Digitalmars-d-debugger
        • Re: ... Rainer Schuetze via Digitalmars-d-debugger
          • ... Michelle Long via Digitalmars-d-debugger
            • ... Stefan Koch via Digitalmars-d-debugger
              • ... WTF Is Wrong with you people? via Digitalmars-d-debugger
              • ... Michelle Long via Digitalmars-d-debugger
                • ... wjoe via Digitalmars-d-debugger

Reply via email to