@@ -158,17 +158,6 @@ def is_reachable(cls, this: hex, other: hex) -> bool:
158
158
# create a flat list of all ancestors of each tested node
159
159
test_nodes = [parent for node in test_nodes for parent in cls .parents .get (node , [])]
160
160
161
- @classmethod
162
- def is_compressed (cls , t : gdb .Type ) -> bool :
163
- type_name = cls .get_basic_type (t ).name
164
- if type_name is None :
165
- # fallback to the GDB type printer for t
166
- type_name = str (t )
167
- # compressed types from a different classLoader have the format <loader_name>::_z_.<type_name>
168
- result = type_name .startswith (cls .compressed_ref_prefix ) or ('::' + cls .compressed_ref_prefix ) in type_name
169
- trace (f'<SVMUtil> - is_compressed({ type_name } ) = { result } ' )
170
- return result
171
-
172
161
@classmethod
173
162
def is_primitive (cls , t : gdb .Type ) -> bool :
174
163
result = cls .get_basic_type (t ).is_scalar
@@ -236,7 +225,7 @@ def __init__(self):
236
225
self .object_type = gdb .lookup_type ("java.lang.Object" )
237
226
self .object_header_type = gdb .lookup_type ("_objhdr" )
238
227
self .stack_type = gdb .lookup_type ("long" )
239
- self .hub_type = gdb .lookup_type ("java.lang.Class " )
228
+ self .hub_type = gdb .lookup_type ("Encoded$Dynamic$Hub " )
240
229
self .classloader_type = gdb .lookup_type ("java.lang.ClassLoader" )
241
230
self .wrapper_types = [gdb .lookup_type (f'java.lang.{ x } ' ) for x in
242
231
["Byte" , "Short" , "Integer" , "Long" , "Float" , "Double" , "Boolean" , "Character" ]
@@ -267,9 +256,24 @@ def get_adr(self, obj: gdb.Value) -> int:
267
256
def is_null (self , obj : gdb .Value ) -> bool :
268
257
return self .get_adr (obj ) == 0
269
258
259
+ def is_compressed (self , t : gdb .Type ) -> bool :
260
+ # for the hub type we always want handle it as compressed as there is no clear distinction in debug info for
261
+ # the hub field, and it may always have an expression in the type's data_location attribute
262
+ if self .get_basic_type (t ) == self .hub_type :
263
+ return True
264
+
265
+ type_name = self .get_basic_type (t ).name
266
+ if type_name is None :
267
+ # fallback to the GDB type printer for t
268
+ type_name = str (t )
269
+ # compressed types from a different classLoader have the format <loader_name>::_z_.<type_name>
270
+ result = type_name .startswith (self .compressed_ref_prefix ) or ('::' + self .compressed_ref_prefix ) in type_name
271
+ trace (f'<SVMUtil> - is_compressed({ type_name } ) = { result } ' )
272
+ return result
273
+
270
274
def get_compressed_oop (self , obj : gdb .Value ) -> int :
271
275
# use compressed ref if available - only compute it if necessary
272
- if obj .type .code == gdb .TYPE_CODE_PTR and SVMUtil .is_compressed (obj .type ):
276
+ if obj .type .code == gdb .TYPE_CODE_PTR and self .is_compressed (obj .type ):
273
277
return int (obj )
274
278
275
279
obj_adr = self .get_adr (obj )
@@ -279,7 +283,7 @@ def get_compressed_oop(self, obj: gdb.Value) -> int:
279
283
# recreate compressed oop from the object address
280
284
# this reverses the uncompress expression from
281
285
# com.oracle.objectfile.elf.dwarf.DwarfInfoSectionImpl#writeIndirectOopConversionExpression
282
- is_hub = self .get_basic_type (obj ) == self .hub_type
286
+ is_hub = self .get_basic_type (obj . type ) == self .hub_type
283
287
compression_shift = self .compression_shift
284
288
num_reserved_bits = int .bit_count (self .reserved_bits_mask )
285
289
num_alignment_bits = int .bit_count (self .object_alignment - 1 )
@@ -299,7 +303,7 @@ def get_compressed_oop(self, obj: gdb.Value) -> int:
299
303
return compressed_oop
300
304
301
305
def adr_str (self , obj : gdb .Value ) -> str :
302
- if not svm_print_address .absolute_adr and SVMUtil .is_compressed (obj .type ):
306
+ if not svm_print_address .absolute_adr and self .is_compressed (obj .type ):
303
307
result = f' @z({ hex (self .get_compressed_oop (obj ))} )'
304
308
else :
305
309
result = f' @({ hex (self .get_adr (obj ))} )'
@@ -375,7 +379,7 @@ def get_java_string(self, obj: gdb.Value, gdb_output_string: bool = False) -> st
375
379
376
380
def get_hub_field (self , obj : gdb .Value ) -> gdb .Value :
377
381
try :
378
- return obj . cast ( self .object_header_type )[self .hub_field_name ]
382
+ return self . cast_to ( obj , self .object_header_type )[self .hub_field_name ]
379
383
except gdb .error :
380
384
return self .null
381
385
@@ -472,7 +476,7 @@ def get_rtt(self, obj: gdb.Value) -> gdb.Type:
472
476
else :
473
477
rtt = gdb .lookup_type (rtt_name )
474
478
475
- if SVMUtil .is_compressed (obj .type ) and not SVMUtil .is_compressed (rtt ):
479
+ if self .is_compressed (obj .type ) and not self .is_compressed (rtt ):
476
480
rtt = self .get_compressed_type (rtt )
477
481
478
482
trace (f'<SVMUtil> - get_rtt({ hex (self .get_adr (obj ))} ) = { rtt_name } ' )
@@ -483,7 +487,7 @@ def cast_to(self, obj: gdb.Value, t: gdb.Type) -> gdb.Value:
483
487
return obj
484
488
485
489
# get objects address, take care of compressed oops
486
- if SVMUtil .is_compressed (t ):
490
+ if self .is_compressed (t ):
487
491
obj_oop = self .get_compressed_oop (obj )
488
492
else :
489
493
obj_oop = self .get_adr (obj )
@@ -501,7 +505,7 @@ def get_uncompressed_type(self, t: gdb.Type) -> gdb.Type:
501
505
# compressed types only exist for java type which are either struct or union
502
506
if t .code != gdb .TYPE_CODE_STRUCT and t .code != gdb .TYPE_CODE_UNION :
503
507
return t
504
- result = self .get_base_class (t ) if SVMUtil .is_compressed (t ) else t
508
+ result = self .get_base_class (t ) if ( self .is_compressed (t ) and t != self . hub_type ) else t
505
509
trace (f'<SVMUtil> - get_uncompressed_type({ t } ) = { result } ' )
506
510
return result
507
511
@@ -546,7 +550,7 @@ def get_compressed_type(self, t: gdb.Type) -> gdb.Type:
546
550
t = SVMUtil .get_basic_type (t )
547
551
# compressed types only exist for java types which are either struct or union
548
552
# do not compress types that already have the compressed prefix
549
- if not self .is_java_type (t ) or SVMUtil .is_compressed (t ):
553
+ if not self .is_java_type (t ) or self .is_compressed (t ):
550
554
return t
551
555
552
556
type_name = t .name
@@ -688,7 +692,7 @@ def children(self) -> Iterable[object]:
688
692
trace ('<SVMPPClass> - children (class field iterator)' )
689
693
if self .__skip_children :
690
694
return
691
- fields = [str (f .name ) for f in SVMUtil .get_all_fields (self .__obj .type , svm_print_static_fields .value ) if f .name != SVMUtil . hub_field_name ]
695
+ fields = [str (f .name ) for f in SVMUtil .get_all_fields (self .__obj .type , svm_print_static_fields .value ) if f .parent_type != self . __svm_util . object_header_type ]
692
696
for index , f in enumerate (fields ):
693
697
trace (f'<SVMPPClass> - children: field "{ f } "' )
694
698
# apply custom limit only for java objects
@@ -1343,7 +1347,7 @@ def cast_to_rtt(self, obj: gdb.Value, obj_str: str) -> tuple: # tuple[gdb.Value
1343
1347
if static_type .name == rtt .name :
1344
1348
return obj , obj_str
1345
1349
else :
1346
- obj_oop = self .svm_util .get_compressed_oop (obj ) if SVMUtil .is_compressed (rtt ) else self .svm_util .get_adr (obj )
1350
+ obj_oop = self .svm_util .get_compressed_oop (obj ) if self . svm_util .is_compressed (rtt ) else self .svm_util .get_adr (obj )
1347
1351
return obj , f"(('{ rtt .name } ' *)({ obj_oop } ))"
1348
1352
1349
1353
# Define the token specifications
@@ -1389,6 +1393,7 @@ def check(self, expected: str):
1389
1393
raise RuntimeError (f"{ expected } expected after { self .expr [:self .t .end ]} but got { self .sym } " )
1390
1394
1391
1395
def parse (self , completion : bool = False ) -> str :
1396
+ self .svm_util = SVMUtil ()
1392
1397
self .scan ()
1393
1398
if self .sym == "" and completion :
1394
1399
raise self .AutoComplete (gdb .COMPLETE_EXPRESSION )
@@ -1539,7 +1544,7 @@ def params(self, completion: bool = False) -> str:
1539
1544
obj_str += self .t .val
1540
1545
1541
1546
obj = gdb .parse_and_eval (obj_str ) # check if gdb can handle the current param
1542
- if self .svm_util .is_java_type (obj .type ) and SVMUtil .is_compressed (obj .type ):
1547
+ if self .svm_util .is_java_type (obj .type ) and self . svm_util .is_compressed (obj .type ):
1543
1548
# uncompress compressed java params
1544
1549
obj_str = f"(('{ self .svm_util .get_uncompressed_type (SVMUtil .get_basic_type (obj .type )).name } ' *)({ self .svm_util .get_adr (obj )} ))"
1545
1550
param_str += obj_str
@@ -1565,8 +1570,6 @@ def array_index(self, completion: bool = False) -> str:
1565
1570
return i_obj_str
1566
1571
1567
1572
def complete (self , text : str , word : str ): # -> list[str] | int:
1568
- self .svm_util = SVMUtil ()
1569
-
1570
1573
if not svm_print .value :
1571
1574
return gdb .COMPLETE_EXPRESSION
1572
1575
@@ -1580,8 +1583,6 @@ def complete(self, text: str, word: str): # -> list[str] | int:
1580
1583
return gdb .COMPLETE_NONE
1581
1584
1582
1585
def invoke (self , arg : str , from_tty : bool ) -> None :
1583
- self .svm_util = SVMUtil ()
1584
-
1585
1586
if not svm_print .value :
1586
1587
gdb .execute (f"print { arg } " )
1587
1588
return
0 commit comments