Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GR-38416] Implement debug location info #4505

Merged
merged 22 commits into from
May 14, 2022

Conversation

adinn
Copy link
Collaborator

@adinn adinn commented Apr 22, 2022

Implementation PR for issue #4504

This includes location info for parameters and locals that ar ein registers or on the stack.

It does not yet include info for bindings to constants.

Updates to the reference manual will be provided as a separate PR.

@olpaw olpaw self-assigned this Apr 25, 2022
@olpaw olpaw self-requested a review April 25, 2022 07:56
@adinn
Copy link
Collaborator Author

adinn commented Apr 26, 2022

I have now implemented location info for locals/params that are bound to primitive constants or a null oop.
I also fixed an error with compiler generated stack slots where I was using the raw offset instead of rebasing with the frame size.

@fniephaus fniephaus changed the title Implement debug location info [GR-38416] Implement debug location info Apr 27, 2022
@fniephaus fniephaus added this to the 22.2 milestone Apr 27, 2022
* inline.
*/

static final class DwarfLocalProperties {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to simply add an int index field in NativeImageDebugLocalValueInfo instead of managing those indexes externally?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe. ;-)

The reason for making it external is that this is a DWARF-specific property that is being added as an external 'decoration' to the generic model of the code base presented via the DebugInfoProvider and com.oracle.object.debugentry types. The Windows generator might perhaps need to track placement of records associated with locals but, if it does, I wouldn't be able to say whether it needs to do so using an integer offset.

This is actually a special case of a more general problem. The same concern to keep target object-specific decoration separate from generic model types motivates use of the other two external DWARF index classes, DwarfTypeProperties and DwarfClassProperties which are used to decorate TypeEntry, ClassEntry and MethodEntry classes with a variety of different target object-specific properties. These latter cases are more complex not just because there are multiple properties associated with a model object but also because the indexing mechanism can be hierarchical rather than single

I'd like to find a better way to implement decorations that are directly attached to the model objects rather than via all these separate indexes. However, while it might be expedient to simply add a setter to NativeImageDebugLocalValueInfo I feel that would just be a hack for a specific case that did not really address a more general problem.

return false;
}
// values need to be for the same line
if (value.line() != otherValue.line()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious, does it really happen that when we have hi == otherLo that value.line() != otherValue.line() is ever true?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it can happen. The line number here is not for the declaration of the local var but for the infopoint where a location was recorded for the local. So, we can have two successive infopoints with different line numbers that both provide values for the local.

However, your question raises a good point all the same. It is important not to merge Range instances with different lines because the Range objects are used to drive generation of debug line info. However, I am now wondering whether we need to care about the line difference when merging location extents. I don't think the debugger lookup for locations requires that the location ranges conform to the line number ranges. So, I think we can remove this check and rely on the subsequent value comparison to decide whether or not to merge the location extents.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This got folded into the equals method where we do have to test for equality of line numbers.

@olpaw
Copy link
Member

olpaw commented Apr 28, 2022

Testing with svmbuild/hello.helloshows that setting a breakpoint in static method java.lang.Integer#stringSize does not seem to work. If fact this method is not even found with info functions stringSize. If I set a line breakpoint in it I do see something but it looks buggy:

Thread 1 "hello.hello" hit Breakpoint 1, hello.Hello::noInlineManyArgs(int, int, int, int, int, int, int, int, int, float, float, float, float, float, float, float, float, float) (i0=0, i1=1, i2=2, i3=3, i4=4, i5=5, i6=6, i7=7, i8=8, f0=0, f1=1.125, f2=2.25, f3=3.375, f4=4.5, f5=5.625, f6=6.75, f7=7.875, f8=9) at hello/Hello.java:187
187	        System.out.println("i0 = " + i0);
(gdb) s
java.lang.StringConcatHelper::mix(long, int) (lengthCoder=5, value=0) at java/lang/StringConcatHelper.java:112
112	        return checkOverflow(lengthCoder + Integer.stringSize(value));
(gdb) 
java.lang.Integer::stringSize (x=0) at java/lang/Integer.java:551
551	        int d = 1;
(gdb) info locals
d = <optimized out>
p = <error reading variable p (Unhandled dwarf expression opcode 0xff)>
i = <optimized out>

Here are the remaining results of info locals within stringSize

552	        if (x >= 0) {
d = <error reading variable d (Unhandled dwarf expression opcode 0x1)>
p = <error reading variable p (Unhandled dwarf expression opcode 0xff)>
i = <optimized out>
(gdb) 
553	            d = 0;
d = <optimized out>
p = <error reading variable p (Unhandled dwarf expression opcode 0xff)>
i = <optimized out>
(gdb) 
554	            x = -x;
d = <optimized out>
p = <error reading variable p (Unhandled dwarf expression opcode 0xff)>
i = <optimized out>
(gdb) 
556	        int p = -10;
d = <optimized out>
p = <error reading variable p (Unhandled dwarf expression opcode 0xff)>
i = <optimized out>
(gdb) 
557	        for (int i = 1; i < 10; i++) {
d = <optimized out>
p = <error reading variable p (Asked for position 0 of stack, stack only has 0 elements on it.)>
i = <optimized out>
(gdb) 
558	            if (x > p)
d = <optimized out>
p = <error reading variable p (Asked for position 0 of stack, stack only has 0 elements on it.)>
i = <error reading variable i (Unhandled dwarf expression opcode 0x1)>
(gdb) 
559	                return i + d;
d = <optimized out>
p = <error reading variable p (Unhandled dwarf expression opcode 0xff)>
i = <optimized out>

@olpaw
Copy link
Member

olpaw commented Apr 28, 2022

But many things are working fine. Like e.g.

Thread 1 "hello.hello" hit Breakpoint 2, java.io.PrintStream::println (this=<optimized out>, x=0x7ffff7c06f08) at java/io/PrintStream.java:1027
1027	        if (getClass() == PrintStream.class) {
(gdb) p x->value->len
$3 = 6
(gdb) set print elements 6
(gdb) p/s x->value->data
$4 = 0x7ffff7c06f00 "i4 = 4"...

or

(gdb) b slowPathNewInstance
Breakpoint 1 at 0x469640: file com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java, line 165.
(gdb) r
Starting program: /home/pwoegere/OLabs/issues/GR-38416/graal/substratevm/svmbuild/hello.hello 
...
Breakpoint 1, com.oracle.svm.core.genscavenge.ThreadLocalAllocation::slowPathNewInstance(org.graalvm.compiler.word.Word *) (objectHeader=0xee05a0) at com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java:165
165	        StackOverflowCheck.singleton().makeYellowZoneAvailable();
(gdb) n
167	            DynamicHub hub = ObjectHeaderImpl.getObjectHeaderImpl().dynamicHubFromObjectHeader(objectHeader);
(gdb) 
169	            Object result = slowPathNewInstanceWithoutAllocating(hub);
(gdb) s
com.oracle.svm.core.genscavenge.ThreadLocalAllocation::slowPathNewInstanceWithoutAllocating(java.lang.Class *) (hub=0xee05a0) at com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java:211
211	        DeoptTester.disableDeoptTesting();
(gdb) p/s hub->name->value->len
$1 = 40
(gdb) set print elements 40
(gdb) p/s hub->name->value->data
$2 = 0xc784d0 "java.util.concurrent.locks.ReentrantLock"...

This is really nice 😎

Copy link
Member

@olpaw olpaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See review comments. Please also tidy up the commit history (remember commit message start with uppercase letter) and fold cleanup commits into their predecessor commits where it makes sense.

This was just the first round of reviewing. I will have another look mid next week.

@adinn
Copy link
Collaborator Author

adinn commented Apr 29, 2022

@olpaw

Testing with svmbuild/hello.helloshows that setting a breakpoint in static method java.lang.Integer#stringSize does not seem to work. If fact this method is not even found with info functions stringSize. If I set a line breakpoint in it I do see something but it looks buggy:

That's actually normal behaviour for gdb with inline only methods. You can't see them using 'info func' but you can break them. The same behaviour was present before this fix.

(gdb) info locals
d =
p = <error reading variable p (Unhandled dwarf expression opcode 0xff)>

Sorry, all those 'error reading variable' messages are because I messed up the constant loc expression generation at DwarfLocSectionImpl.java:340. I managed to delete the line that inserts a short total byte count before the byte block that encodes the DWARF location expression. I'll fix that in the rework.

@adinn
Copy link
Collaborator Author

adinn commented May 3, 2022

@olpaw I addressed all the issues form your original review. While i was fixing the error I introduced into writing of primitive and null constants I also added the code for writing constant object values (i.e. reference to initial heap objects). So, you can now see things like String constants, albeit as references -- you have to execute (gdb) print stringvar->value to see the actual byte array contents.

I'll squash the commits down and check for proper commit messages next.

@adinn adinn force-pushed the debug_location_info branch from de58d6f to 7b2fa60 Compare May 4, 2022 10:12
@adinn
Copy link
Collaborator Author

adinn commented May 4, 2022

@olpaw I just added what I believe is the last remaining missing functionality for the localvars patch i.e. I extended the tests to check bindings for constant values.

n.b. It's not actually visible at source debugging level that the test method inlineReceiveConstants is being passed arguments that are bound to constants. Nor is it visible that the locals it computes and prints are also bound to constants. However, I designed the calling and called routines to ensure that they get bound to constants and then verified by stepping through the code that the appropriate numeric and object (String) values are actually loaded from the initial heap. So, I am confident that this test will catch any breakage if the code that assembles the initial heap changes the way they are presented.

}

// map from compiler AArch64 register indices to corresponding dwarf AArch64 register index
private static final int[] GRAAL_AARCH64_TO_DWARF_REG_MAP = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a much simpler way to construct GRAAL_AARCH64_TO_DWARF_REG_MAP

b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLocSectionImpl.java
--- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLocSectionImpl.java	(revision Staged)
+++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLocSectionImpl.java	(date 1651762016801)
@@ -599,82 +601,18 @@
         V30(94),
         V31(95);
 
-        public final int encoding;
+        private final int encoding;
+
+        public int getEncoding() {
+            return encoding;
+        }
 
         DwarfRegEncodingAArch64(int encoding) {
             this.encoding = encoding;
         }
     }
 
-    // map from compiler AArch64 register indices to corresponding dwarf AArch64 register index
-    private static final int[] GRAAL_AARCH64_TO_DWARF_REG_MAP = {
-                    DwarfRegEncodingAArch64.R0.encoding,
-                    DwarfRegEncodingAArch64.R1.encoding,
-                    DwarfRegEncodingAArch64.R2.encoding,
-                    DwarfRegEncodingAArch64.R3.encoding,
-                    DwarfRegEncodingAArch64.R4.encoding,
-                    DwarfRegEncodingAArch64.R5.encoding,
-                    DwarfRegEncodingAArch64.R6.encoding,
-                    DwarfRegEncodingAArch64.R7.encoding,
-                    DwarfRegEncodingAArch64.R8.encoding,
-                    DwarfRegEncodingAArch64.R9.encoding,
-                    DwarfRegEncodingAArch64.R10.encoding,
-                    DwarfRegEncodingAArch64.R11.encoding,
-                    DwarfRegEncodingAArch64.R12.encoding,
-                    DwarfRegEncodingAArch64.R13.encoding,
-                    DwarfRegEncodingAArch64.R14.encoding,
-                    DwarfRegEncodingAArch64.R15.encoding,
-                    DwarfRegEncodingAArch64.R16.encoding,
-                    DwarfRegEncodingAArch64.R17.encoding,
-                    DwarfRegEncodingAArch64.R18.encoding,
-                    DwarfRegEncodingAArch64.R19.encoding,
-                    DwarfRegEncodingAArch64.R20.encoding,
-                    DwarfRegEncodingAArch64.R21.encoding,
-                    DwarfRegEncodingAArch64.R22.encoding,
-                    DwarfRegEncodingAArch64.R23.encoding,
-                    DwarfRegEncodingAArch64.R24.encoding,
-                    DwarfRegEncodingAArch64.R25.encoding,
-                    DwarfRegEncodingAArch64.R26.encoding,
-                    DwarfRegEncodingAArch64.R27.encoding,
-                    DwarfRegEncodingAArch64.R28.encoding,
-                    DwarfRegEncodingAArch64.R29.encoding,
-                    DwarfRegEncodingAArch64.R30.encoding,
-                    DwarfRegEncodingAArch64.R31.encoding,
-                    DwarfRegEncodingAArch64.ZR.encoding,
-                    DwarfRegEncodingAArch64.SP.encoding,
-                    DwarfRegEncodingAArch64.V0.encoding,
-                    DwarfRegEncodingAArch64.V1.encoding,
-                    DwarfRegEncodingAArch64.V2.encoding,
-                    DwarfRegEncodingAArch64.V3.encoding,
-                    DwarfRegEncodingAArch64.V4.encoding,
-                    DwarfRegEncodingAArch64.V5.encoding,
-                    DwarfRegEncodingAArch64.V6.encoding,
-                    DwarfRegEncodingAArch64.V7.encoding,
-                    DwarfRegEncodingAArch64.V8.encoding,
-                    DwarfRegEncodingAArch64.V9.encoding,
-                    DwarfRegEncodingAArch64.V10.encoding,
-                    DwarfRegEncodingAArch64.V11.encoding,
-                    DwarfRegEncodingAArch64.V12.encoding,
-                    DwarfRegEncodingAArch64.V13.encoding,
-                    DwarfRegEncodingAArch64.V14.encoding,
-                    DwarfRegEncodingAArch64.V15.encoding,
-                    DwarfRegEncodingAArch64.V16.encoding,
-                    DwarfRegEncodingAArch64.V17.encoding,
-                    DwarfRegEncodingAArch64.V18.encoding,
-                    DwarfRegEncodingAArch64.V19.encoding,
-                    DwarfRegEncodingAArch64.V20.encoding,
-                    DwarfRegEncodingAArch64.V21.encoding,
-                    DwarfRegEncodingAArch64.V22.encoding,
-                    DwarfRegEncodingAArch64.V23.encoding,
-                    DwarfRegEncodingAArch64.V24.encoding,
-                    DwarfRegEncodingAArch64.V25.encoding,
-                    DwarfRegEncodingAArch64.V26.encoding,
-                    DwarfRegEncodingAArch64.V27.encoding,
-                    DwarfRegEncodingAArch64.V28.encoding,
-                    DwarfRegEncodingAArch64.V29.encoding,
-                    DwarfRegEncodingAArch64.V30.encoding,
-                    DwarfRegEncodingAArch64.V31.encoding,
-    };
+    private static final int[] GRAAL_AARCH64_TO_DWARF_REG_MAP = Arrays.stream(DwarfRegEncodingAArch64.values()).mapToInt(DwarfRegEncodingAArch64::getEncoding).toArray();
 
     // register numbers used by DWARF for AMD64 registers
     public enum DwarfRegEncodingAMD64 {

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is the right thing to do. See below for details.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed by documenting the current code as per below.

@adinn adinn force-pushed the debug_location_info branch from 2165969 to d57108d Compare May 12, 2022 09:59
@adinn adinn force-pushed the debug_location_info branch from 54a4afc to 3bdfb48 Compare May 13, 2022 13:13
@adinn adinn force-pushed the debug_location_info branch from 3bdfb48 to 1c651c8 Compare May 13, 2022 13:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants