From ba0619f2b56a0c7cdebdff13173f586795947a9a Mon Sep 17 00:00:00 2001
From: Nick Gasson <nick.gasson@arm.com>
Date: Tue, 18 May 2021 21:01:41 +0800
Subject: [PATCH] perf jvmti: Fix demangling Java symbols

mainline inclusion
from mainline-v5.7
commit 0bdf31811be08f93a4bea015d6666df4455c5180
category: bugfix
bugzilla: NA
CVE: NA

-------------------------------------------------

For a Java method signature like:

    Ljava/lang/AbstractStringBuilder;appendChars(Ljava/lang/String;II)V

The demangler produces:

    void class java.lang.AbstractStringBuilder.appendChars(class java.lang., shorttring., int, int)

The arguments should be (java.lang.String, int, int) but the demangler
interprets the "S" in String as the type code for "short". Correct this
and two other minor things:

- There is no "bool" type in Java, should be "boolean".

- The demangler prepends "class" to every Java class name. This is not
  standard Java syntax and it wastes a lot of horizontal space if the
  signature is long. Remove this as there isn't any ambiguity between
  class names and primitives.

Committer notes:

This was split from a larger patch that also added a java demangler
'perf test' entry, that, before this patch shows the error being fixed
by it:

  $ perf test java
  65: Demangle Java                                         : FAILED!
  $ perf test -v java
  Couldn't bump rlimit(MEMLOCK), failures may take place when creating BPF maps, etc
  65: Demangle Java                                         :
  --- start ---
  test child forked, pid 307264
  FAILED: Ljava/lang/StringLatin1;equals([B[B)Z: bool class java.lang.StringLatin1.equals(byte[], byte[]) != boolean java.lang.StringLatin1.equals(byte[], byte[])
  FAILED: Ljava/util/zip/ZipUtils;CENSIZ([BI)J: long class java.util.zip.ZipUtils.CENSIZ(byte[], int) != long java.util.zip.ZipUtils.CENSIZ(byte[], int)
  FAILED: Ljava/util/regex/Pattern$BmpCharProperty;match(Ljava/util/regex/Matcher;ILjava/lang/CharSequence;)Z: bool class java.util.regex.Pattern$BmpCharProperty.match(class java.util.regex.Matcher., int, class java.lang., charhar, shortequence) != boolean java.util.regex.Pattern$BmpCharProperty.match(java.util.regex.Matcher, int, java.lang.CharSequence)
  FAILED: Ljava/lang/AbstractStringBuilder;appendChars(Ljava/lang/String;II)V: void class java.lang.AbstractStringBuilder.appendChars(class java.lang., shorttring., int, int) != void java.lang.AbstractStringBuilder.appendChars(java.lang.String, int, int)
  FAILED: Ljava/lang/Object;<init>()V: void class java.lang.Object<init>() != void java.lang.Object<init>()
  test child finished with -1
  ---- end ----
  Demangle Java: FAILED!
  $

After applying this patch:

  $ perf test  java
  65: Demangle Java                                         : Ok
  $

Signed-off-by: Nick Gasson <nick.gasson@arm.com>
Reviewed-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Ian Rogers <irogers@google.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lore.kernel.org/lkml/20200427061520.24905-4-nick.gasson@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Zhichang Yuan <erik.yuan@arm.com>
Reviewed-by: Yang Jihong <yangjihong1@huawei.com>
Signed-off-by: Cheng Jian <cj.chengjian@huawei.com>
---
 tools/perf/util/demangle-java.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/demangle-java.c b/tools/perf/util/demangle-java.c
index e4c486756053..c384f66a77fe 100644
--- a/tools/perf/util/demangle-java.c
+++ b/tools/perf/util/demangle-java.c
@@ -15,7 +15,7 @@ enum {
 	MODE_CLASS  = 1,
 	MODE_FUNC   = 2,
 	MODE_TYPE   = 3,
-	MODE_CTYPE  = 3, /* class arg */
+	MODE_CTYPE  = 4, /* class arg */
 };
 
 #define BASE_ENT(c, n)	[c - 'A']=n
@@ -27,7 +27,7 @@ static const char *base_types['Z' - 'A' + 1] = {
 	BASE_ENT('I', "int" ),
 	BASE_ENT('J', "long" ),
 	BASE_ENT('S', "short" ),
-	BASE_ENT('Z', "bool" ),
+	BASE_ENT('Z', "boolean" ),
 };
 
 /*
@@ -59,15 +59,16 @@ __demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int
 
 		switch (*q) {
 		case 'L':
-			if (mode == MODE_PREFIX || mode == MODE_CTYPE) {
-				if (mode == MODE_CTYPE) {
+			if (mode == MODE_PREFIX || mode == MODE_TYPE) {
+				if (mode == MODE_TYPE) {
 					if (narg)
 						rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
 					narg++;
 				}
-				rlen += scnprintf(buf + rlen, maxlen - rlen, "class ");
 				if (mode == MODE_PREFIX)
 					mode = MODE_CLASS;
+				else
+					mode = MODE_CTYPE;
 			} else
 				buf[rlen++] = *q;
 			break;
@@ -120,7 +121,7 @@ __demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int
 			if (mode != MODE_CLASS && mode != MODE_CTYPE)
 				goto error;
 			/* safe because at least one other char to process */
-			if (isalpha(*(q + 1)))
+			if (isalpha(*(q + 1)) && mode == MODE_CLASS)
 				rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
 			if (mode == MODE_CLASS)
 				mode = MODE_FUNC;
-- 
GitLab