This is an automated email from the ASF dual-hosted git repository.

entl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new c2e5944e6c Corrected array and String inspection for various versions 
of GDB.
c2e5944e6c is described below

commit c2e5944e6c3ab56ffc28882817e81cc3e25cba45
Author: Martin Entlicher <martin.entlic...@oracle.com>
AuthorDate: Mon Apr 11 09:55:44 2022 +0200

    Corrected array and String inspection for various versions of GDB.
---
 .../debugger/displayer/JavaVariablesDisplayer.java | 397 +++++++++++++++------
 1 file changed, 296 insertions(+), 101 deletions(-)

diff --git 
a/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/displayer/JavaVariablesDisplayer.java
 
b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/displayer/JavaVariablesDisplayer.java
index eed890c473..a4009387e5 100644
--- 
a/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/displayer/JavaVariablesDisplayer.java
+++ 
b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/displayer/JavaVariablesDisplayer.java
@@ -28,6 +28,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.WeakHashMap;
 
 import org.netbeans.modules.nativeimage.api.debug.EvaluateException;
 import org.netbeans.modules.nativeimage.api.debug.NIDebugger;
@@ -54,7 +55,11 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
 
     private static final String[] STRING_TYPES = new String[] { 
String.class.getName(), StringBuilder.class.getName(), 
StringBuffer.class.getName() };
 
+    // Variable names with this prefix contain space-separated variable name 
and expression path
+    private static final String PREFIX_VAR_PATH = "{ ";
+
     private NIDebugger debugger;
+    private final Map<NIVariable, String> variablePaths = 
Collections.synchronizedMap(new WeakHashMap<>());
 
     public JavaVariablesDisplayer() {
     }
@@ -67,28 +72,40 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
     public NIVariable[] displayed(NIVariable[] variables) {
         List<NIVariable> displayedVars = new ArrayList<>(variables.length);
         for (NIVariable var : variables) {
-           String value = var.getValue();
+            String value = var.getValue();
             if (UNSET.equals(value)) {
                 continue;
             }
+            if (var instanceof AbstractVar) {
+                // Translated already
+                displayedVars.add(var);
+                continue;
+            }
+            String name = var.getName();
+            String path = null;
+            if (name.startsWith(PREFIX_VAR_PATH)) {
+                int i = name.indexOf(' ', PREFIX_VAR_PATH.length());
+                if (i > 0) {
+                    path = name.substring(i + 1);
+                    name = name.substring(PREFIX_VAR_PATH.length(), i);
+                }
+            }
+            if (path != null) {
+                variablePaths.put(var, path);
+            }
             int nch = var.getNumChildren();
             NIVariable displayedVar;
             if (nch == 0) {
-                String name = var.getName();
-                if (!name.equals(getNameOrIndex(name))) {
-                    displayedVar = new Var(var);
-                } else {
-                    displayedVar = var;
-                }
+                displayedVar = new Var(var, name, path);
             } else {
                 NIVariable[] children = var.getChildren();
-                NIVariable[] subChildren = children[0].getChildren();
+                NIVariable[] subChildren = children.length > 0 ? 
children[0].getChildren() : new NIVariable[]{};
                 // Check for Array
                 if (subChildren.length == 3 &&
                         //HUB.equals(subChildren[0].getName()) &&
                         ARRAY_LENGTH.equals(subChildren[1].getName()) &&
                         ARRAY.equals(subChildren[2].getName())) {
-                    displayedVar = new ArrayVar(var, subChildren[1], 
subChildren[2]);
+                    displayedVar = new ArrayVar(var, name, path, 
subChildren[1], subChildren[2]);
                 } else {
                     // Check for String
                     String type = getSimpleType(var.getType());
@@ -103,22 +120,22 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
                         }
                     }
                     if (likeString) {
-                        displayedVar = new StringVar(var, type, isString ? 
null : subChildren);
+                        displayedVar = new StringVar(var, name, path, type, 
isString ? null : subChildren);
                     } else {
                         if (children.length == 1 && 
PUBLIC.equals(children[0].getName())) {
                             // Object children
-                            displayedVar = new ObjectVar(var, subChildren);
+                            displayedVar = new ObjectVar(var, name, path, 
subChildren);
                         } else {
-                            String name = var.getName();
-                            if (!name.equals(getNameOrIndex(name))) {
-                                displayedVar = new Var(var);
-                            } else {
-                                displayedVar = var;
-                            }
+                            displayedVar = new Var(var, name, path);
                         }
                     }
                 }
             }
+            if (displayedVar != var) {
+                synchronized (variablePaths) {
+                    variablePaths.put(displayedVar, variablePaths.get(var));
+                }
+            }
             displayedVars.add(displayedVar);
         }
         return displayedVars.toArray(new NIVariable[displayedVars.size()]);
@@ -234,7 +251,7 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
 
     private String readArray(NIVariable lengthVariable, int itemSize) {
         int length = Integer.parseInt(lengthVariable.getValue());
-        String expressionPath = lengthVariable.getExpressionPath();
+        String expressionPath = getExpressionPath(lengthVariable);
         if (expressionPath != null && !expressionPath.isEmpty()) {
             String addressExpr = "&" + expressionPath;
             return debugger.readMemory(addressExpr, 4, length * itemSize); // 
length has 4 bytes
@@ -244,7 +261,7 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
 
     private String readArray(NIVariable lengthVariable, int offset, int 
itemSize) {
         int length = Integer.parseInt(lengthVariable.getValue());
-        String expressionPath = lengthVariable.getExpressionPath();
+        String expressionPath = getExpressionPath(lengthVariable);
         if (expressionPath != null && !expressionPath.isEmpty()) {
             String addressExpr = "&" + expressionPath;
             return debugger.readMemory(addressExpr, 4 + offset, length * 
itemSize); // length has 4 bytes
@@ -281,14 +298,63 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
         return null;
     }
 
-    private class StringVar implements NIVariable {
+    private static boolean isPrimitiveArray(String type) {
+        int i = type.indexOf(' ');
+        if (i < 0) {
+            return false;
+        }
+        String name = type.substring(0, i);
+        switch (name) {
+            case "boolean":
+            case "byte":
+            case "char":
+            case "short":
+            case "int":
+            case "long":
+            case "float":
+            case "double":
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private String getExpressionPath(NIVariable var) {
+        String path = var.getExpressionPath();
+        if (!path.isEmpty()) {
+            return path;
+        } else {
+            return createExpressionPath(var);
+        }
+    }
+
+    /** Used as a fallback when {@link NIVariable#getExpressionPath()} does 
not provide anything. */
+    private String createExpressionPath(NIVariable var) {
+        String path = variablePaths.get(var);
+        if (path != null) {
+            return path;
+        }
+        path = var.getName();
+        NIVariable parent = var.getParent();
+        if (parent == null) {
+            return path;
+        } else {
+            String parentPath = createExpressionPath(parent);
+            if (PUBLIC.equals(path)) {
+                return parentPath;
+            } else {
+                return parentPath + '.' + path;
+            }
+        }
+    }
+
+    private class StringVar extends AbstractVar {
 
-        private final NIVariable var;
         private final String type;
         private final NIVariable[] children;
 
-        StringVar(NIVariable var, String type, NIVariable[] children) {
-            this.var = var;
+        StringVar(NIVariable var, String name, String path, String type, 
NIVariable[] children) {
+            super(var, name, path);
             this.type = type;
             this.children = children;
         }
@@ -298,11 +364,6 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
             return var.getFrame();
         }
 
-        @Override
-        public String getName() {
-            return getNameOrIndex(var.getName());
-        }
-
         @Override
         public String getType() {
             return type;
@@ -337,7 +398,7 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
                 } catch (NumberFormatException ex) {
                 }
             }
-            String hexArray = readArray(lengthVariable, coder == -1 ? 4 : 0, 
2);
+            String hexArray = readArray(lengthVariable, 0, 2);
             if (hexArray != null) {
                 switch (coder) {
                     case 0: // Compressed String on JDK 9+
@@ -347,19 +408,105 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
                     default: // UTF-16 String on JDK 8
                         return parseUTF16(hexArray, length);
                 }
-            } else { // legacy code
-                String arrayExpression = getArrayExpression(arrayVariable);
-                char[] characters = new char[length];
+            } else { // legacy code for older gdb version (less than 10.x)
+                String arrayExpression = 
JavaVariablesDisplayer.this.getExpressionPath(arrayVariable); 
//getArrayExpression(arrayVariable);
+                NIFrame frame = var.getFrame();
                 try {
-                    for (int i = 0; i < length; i++) {
-                        NIVariable charVar = debugger.evaluate(arrayExpression 
+ "[" + i + "]", null, var.getFrame());
-                        String charStr = charVar.getValue();
-                        characters[i] = charStr.charAt(charStr.length() > 1 ? 
1 : 0);
+                    NIVariable charVar = debugger.evaluate(arrayExpression + 
"[0]", null, frame);
+                    if ("byte".equals(charVar.getType())) {
+                        // bytes to be parsed to String
+                        switch (coder) {
+                            case 0: // Compressed String on JDK 9+
+                                return parseLatin1(arrayExpression, frame, 
length);
+                            case 1: // UTF-16 String on JDK 9+
+                                return parseUTF16(arrayExpression, frame, 
length/2);
+                            default: // UTF-16 String on JDK 8
+                                return parseUTF16(arrayExpression, frame, 
length);
+                        }
+                    } else {
+                        char[] characters = new char[length];
+                        for(int i = 0; ; ) {
+                            String charStr = charVar.getValue();
+                            characters[i] = parseCharacter(charStr);
+                            if (++i >= length) {
+                                break;
+                            }
+                            charVar = debugger.evaluate(arrayExpression + "[" 
+ i + "]", null, frame);
+                        }
+                        return new String(characters);
                     }
                 } catch (EvaluateException ex) {
                     return ex.getLocalizedMessage();
                 }
-                return new String(characters);
+            }
+        }
+
+        private char parseCharacter(String charValue) {
+            if (charValue.startsWith("'") && charValue.endsWith("'")) {
+                charValue = charValue.substring(1, charValue.length() - 1);
+            }
+            byte b0, b1;
+            if (charValue.startsWith("\\\\x")) {
+                // hexadecimal
+                b1 = parseByte(charValue, 3);
+                b0 = parseByte(charValue, 5);
+            } else {
+                int[] pos = new int[] {0};
+                try {
+                    b1 = getByteFromChar(charValue, pos);
+                    charValue = charValue.substring(pos[0]);
+                    b0 = getByteFromChar(charValue, pos);
+                } catch (NumberFormatException nfex) {
+                    // octal does not fit into byte
+                    try {
+                        return (char) Short.parseShort(charValue.substring(2), 
8);
+                    } catch (NumberFormatException ex) {
+                        return charValue.charAt(0);
+                    }
+                }
+            }
+            CharsetDecoder cd = Charset.forName("utf-16").newDecoder(); // 
NOI18N
+            byte[] bytes = new byte[] {b1, b0};
+            ByteBuffer buffer = ByteBuffer.allocate(2);
+            buffer.rewind();
+            buffer.put(b0);
+            buffer.put(b1);
+            buffer.rewind();
+            try {
+                char c = cd.decode(buffer).get();
+                return c;
+            } catch (CharacterCodingException ex) {
+                return charValue.charAt(0);
+            }
+        }
+
+        private byte getByteFromChar(String charValue, int[] pos) {
+            if (charValue.startsWith("\\\\")) {
+                pos[0] += 2;
+                char c = charValue.charAt(2);
+                if (Character.isDigit(c)) {
+                    // octal
+                    pos[0] += 3;
+                    return Byte.parseByte(charValue.substring(2, 5), 8);
+                }
+                pos[0]++;
+                switch (c) {
+                    case 'a': return 7; // BEL
+                    case 'b': return 8; // Backspace
+                    case 't': return 9; // TAB
+                    case 'n': return 10; // LF
+                    case 'v': return 11; // VT
+                    case 'f': return 12; // FF
+                    case 'r': return 13; // CR
+                    case '\\':
+                        pos[0]++; // Two back slashes
+                        return (byte) c;
+                    default:
+                        return (byte) c;
+                }
+            } else {
+                pos[0] += 1;
+                return (byte) charValue.charAt(0);
             }
         }
 
@@ -411,6 +558,47 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
             return (byte) (Integer.parseInt(hex, 16) & 0xFF);
         }
 
+        private String parseUTF16(String arrayExpression, NIFrame frame, int 
length) throws EvaluateException {
+            CharsetDecoder cd = Charset.forName("utf-16").newDecoder(); // 
NOI18N
+            ByteBuffer buffer = ByteBuffer.allocate(2);
+            char[] characters = new char[length];
+            for (int i = 0; i < length; i++) {
+                NIVariable byteVar = debugger.evaluate(arrayExpression + "[" + 
(2*i) + "]", null, frame);
+                byte b1 = Byte.parseByte(byteVar.getValue());
+                byteVar = debugger.evaluate(arrayExpression + "[" + (2*i+1) + 
"]", null, frame);
+                byte b0 = Byte.parseByte(byteVar.getValue());
+                buffer.rewind();
+                buffer.put(b0);
+                buffer.put(b1);
+                buffer.rewind();
+                try {
+                    char c = cd.decode(buffer).get();
+                    characters[i] = c;
+                } catch (CharacterCodingException ex) {
+                }
+            }
+            return new String(characters);
+        }
+
+        private String parseLatin1(String arrayExpression, NIFrame frame, int 
length) throws EvaluateException {
+            CharsetDecoder cd = Charset.forName("latin1").newDecoder(); // 
NOI18N
+            ByteBuffer buffer = ByteBuffer.allocate(1);
+            char[] characters = new char[length];
+            for (int i = 0; i < length; i++) {
+                NIVariable byteVar = debugger.evaluate(arrayExpression + "[" + 
i + "]", null, frame);
+                byte b = Byte.parseByte(byteVar.getValue());
+                buffer.rewind();
+                buffer.put(b);
+                buffer.rewind();
+                try {
+                    char c = cd.decode(buffer).get();
+                    characters[i] = c;
+                } catch (CharacterCodingException ex) {
+                }
+            }
+            return new String(characters);
+        }
+
         @Override
         public int getNumChildren() {
             return children != null ? children.length : 0;
@@ -426,21 +614,16 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
             return var.getParent();
         }
 
-        @Override
-        public String getExpressionPath() {
-            return var.getExpressionPath();
-        }
     }
 
-    private class ArrayVar implements NIVariable {
+    private class ArrayVar extends AbstractVar {
 
-        private final NIVariable var;
         private final NIVariable lengthVariable;
         private final int length;
         private final NIVariable array;
 
-        ArrayVar(NIVariable var, NIVariable lengthVariable, NIVariable array) {
-            this.var = var;
+        ArrayVar(NIVariable var, String name, String path, NIVariable 
lengthVariable, NIVariable array) {
+            super(var, name, path);
             this.lengthVariable = lengthVariable;
             int arrayLength;
             try {
@@ -462,11 +645,6 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
             return var.getParent();
         }
 
-        @Override
-        public String getName() {
-            return getNameOrIndex(var.getName());
-        }
-
         @Override
         public String getType() {
             return displayType(var.getType());
@@ -499,38 +677,45 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
             }
 
             String arrayAddress = null;
-            String expressionPath = lengthVariable.getExpressionPath();
-            if (expressionPath != null && !expressionPath.isEmpty()) {
-                String addressExpr = "&" + expressionPath;
-                NIVariable addressVariable;
-                try {
-                    addressVariable = debugger.evaluate(addressExpr, null, 
lengthVariable.getFrame());
-                } catch (EvaluateException ex) {
-                    addressVariable = null;
-                }
-                if (addressVariable != null) {
-                    String address = addressVariable.getValue();
-                    address = address.toLowerCase();
-                    if (address.startsWith("0x")) {
-                        arrayAddress = address;
+            if (isPrimitiveArray(array.getType())) {
+                String expressionPath = 
JavaVariablesDisplayer.this.getExpressionPath(lengthVariable);
+                if (expressionPath != null && !expressionPath.isEmpty()) {
+                    String addressExpr = "&" + expressionPath;
+                    NIVariable addressVariable;
+                    try {
+                        addressVariable = debugger.evaluate(addressExpr, null, 
lengthVariable.getFrame());
+                    } catch (EvaluateException ex) {
+                        addressVariable = null;
+                    }
+                    if (addressVariable != null) {
+                        String address = addressVariable.getValue();
+                        address = address.toLowerCase();
+                        if (address.startsWith("0x")) {
+                            arrayAddress = address;
+                        }
                     }
                 }
             }
             NIVariable[] elements = new NIVariable[to - from];
             try {
                 if (arrayAddress != null) {
-                    String itemExpression = "*(" + getSimpleType(getType()) + 
"*)(" + arrayAddress + "+";
+                    int offset = (getTypeSize(getType()) == 8) ? 8 : 4;
+                    String itemExpression = "*(((" + getSimpleType(getType()) 
+ "*)(" + arrayAddress + "+"+offset+"))+";
                     int size = getTypeSize(getType());
-                    int offset = 4 + from*size;
                     for (int i = from; i < to; i++) {
-                        NIVariable element = debugger.evaluate(itemExpression 
+ offset + ")", Integer.toString(i), var.getFrame());
-                        offset += size;
+                        String expr = itemExpression + i + ")";
+                        NIVariable element = debugger.evaluate(expr, 
Integer.toString(i), var.getFrame());
+                        // When gdb could retrieve variable address, it did 
resolve the expression path.
+                        // Thus there is no need to remember it in 
variablePaths.
                         elements[i - from] = element;
                     }
                 } else {
-                    String arrayExpression = getArrayExpression(array);
+                    String arrayExpression = 
JavaVariablesDisplayer.this.getExpressionPath(array);
                     for (int i = from; i < to; i++) {
-                        NIVariable element = debugger.evaluate(arrayExpression 
+ "[" + i + "]", Integer.toString(i), var.getFrame());
+                        String expr = arrayExpression + "[" + i + "]";
+                        String namePath = PREFIX_VAR_PATH + 
Integer.toString(i) + ' ' + expr;
+                        NIVariable element = debugger.evaluate(expr, namePath, 
var.getFrame());
+                        variablePaths.put(element, expr);
                         elements[i - from] = element;
                     }
                 }
@@ -540,19 +725,14 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
             return elements;
         }
 
-        @Override
-        public String getExpressionPath() {
-            return var.getExpressionPath();
-        }
     }
 
-    private class ObjectVar implements NIVariable {
+    private class ObjectVar extends AbstractVar {
 
-        private final NIVariable var;
         private final NIVariable[] children;
 
-        ObjectVar(NIVariable var, NIVariable[] children) {
-            this.var = var;
+        ObjectVar(NIVariable var, String name, String path, NIVariable[] 
children) {
+            super(var, name, path);
             this.children = children;
         }
 
@@ -566,11 +746,6 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
             return var.getParent();
         }
 
-        @Override
-        public String getName() {
-            return getNameOrIndex(var.getName());
-        }
-
         @Override
         public String getType() {
             return displayType(findRuntimeType());
@@ -603,18 +778,13 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
             return getObjectChildren(children, from, to);
         }
 
-        @Override
-        public String getExpressionPath() {
-            return var.getExpressionPath();
-        }
-
         private String findRuntimeType() {
             NIVariable hub = findChild(HUB, children);
             if (hub != null) {
                 NIVariable pub = findChild(PUBLIC, hub.getChildren());
                 NIVariable nameVar = findChild(NAME, pub.getChildren());
                 if (nameVar != null) {
-                    String name = new StringVar(nameVar, null, 
null).getValue();
+                    String name = new StringVar(nameVar, varName, varPath, 
null, null).getValue();
                     if (!name.isEmpty()) {
                         return name;
                     }
@@ -624,12 +794,10 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
         }
     }
 
-    private class Var implements NIVariable {
-
-        private final NIVariable var;
+    private class Var extends AbstractVar {
 
-        Var(NIVariable var) {
-            this.var = var;
+        Var(NIVariable var, String name, String path) {
+            super(var, name, path);
         }
 
         @Override
@@ -642,11 +810,6 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
             return var.getParent();
         }
 
-        @Override
-        public String getName() {
-            return getNameOrIndex(var.getName());
-        }
-
         @Override
         public String getType() {
             return var.getType();
@@ -672,9 +835,41 @@ public final class JavaVariablesDisplayer implements 
VariableDisplayer {
             return var.getChildren();
         }
 
+    }
+
+    private abstract class AbstractVar implements NIVariable {
+
+        protected final NIVariable var;
+        protected final String varName;
+        protected final String varPath;
+
+        AbstractVar(NIVariable var, String varName, String varPath) {
+            this.var = var;
+            this.varName = varName;
+            this.varPath = varPath;
+        }
+
         @Override
-        public String getExpressionPath() {
-            return var.getExpressionPath();
+        public final String getName() {
+            if (varName != null) {
+                return varName;
+            }
+            return getNameOrIndex(var.getName());
+        }
+
+        @Override
+        public final String getExpressionPath() {
+            if (varPath != null) {
+                return varPath;
+            } else {
+                String path = var.getExpressionPath();
+                if (!path.isEmpty()) {
+                    return path;
+                } else {
+                    path = variablePaths.get(var);
+                    return path != null ? path : getName();
+                }
+            }
         }
     }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org
For additional commands, e-mail: commits-h...@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists

Reply via email to