Ai
1 Star 0 Fork 24

Benshuai5D/openjdk-21

forked from src-openEuler/openjdk-21
关闭
 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
huawei-heap-dump-redact-support.patch 166.70 KB
一键复制 编辑 原始数据 按行查看 历史
Benshuai5D 提交于 2025-05-21 01:38 +08:00 . sync master to openEuler-24.03-LTS
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084
Date: Fri, 14 Mar 2025 22:08:38 +0800
Subject: heap-dump-redact-support
---
src/hotspot/os/linux/os_linux.cpp | 37 +-
src/hotspot/os/linux/os_linux.hpp | 54 ++
src/hotspot/share/oops/annotations.hpp | 1 +
src/hotspot/share/runtime/arguments.cpp | 24 +
src/hotspot/share/runtime/globals.hpp | 18 +
src/hotspot/share/runtime/vmStructs.cpp | 12 +-
src/hotspot/share/services/heapDumper.cpp | 693 +++++++++++++++++-
src/hotspot/share/services/heapRedactor.cpp | 676 +++++++++++++++++
src/hotspot/share/services/heapRedactor.hpp | 225 ++++++
src/hotspot/share/services/writeableFlags.cpp | 7 +
.../share/classes/sun/jvm/hotspot/HSDB.java | 19 +-
.../classes/sun/jvm/hotspot/SALauncher.java | 46 +-
.../sun/jvm/hotspot/oops/Annotation.java | 70 ++
.../classes/sun/jvm/hotspot/oops/Field.java | 10 +
.../sun/jvm/hotspot/oops/InstanceKlass.java | 6 +
.../classes/sun/jvm/hotspot/tools/JMap.java | 63 +-
.../hotspot/utilities/AnnotationArray2D.java | 62 ++
.../hotspot/utilities/HeapHprofBinWriter.java | 419 ++++++++++-
.../jvm/hotspot/utilities/HeapRedactor.java | 454 ++++++++++++
.../share/classes/sun/tools/jmap/JMap.java | 258 ++++++-
20 files changed, 3088 insertions(+), 66 deletions(-)
create mode 100644 src/hotspot/share/services/heapRedactor.cpp
create mode 100644 src/hotspot/share/services/heapRedactor.hpp
create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Annotation.java
create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AnnotationArray2D.java
create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapRedactor.java
diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp
index 3cb529bc8..43ee4b7db 100644
--- a/src/hotspot/os/linux/os_linux.cpp
+++ b/src/hotspot/os/linux/os_linux.cpp
@@ -4587,6 +4587,12 @@ os::Linux::jboltLog_precalc_t os::Linux::_jboltLog_precalc;
os::Linux::jboltLog_do_t os::Linux::_jboltLog_do;
os::Linux::jboltMerge_judge_t os::Linux::_jboltMerge_judge;
#endif // INCLUDE_JBOLT
+os::Linux::heap_dict_add_t os::Linux::_heap_dict_add;
+os::Linux::heap_dict_lookup_t os::Linux::_heap_dict_lookup;
+os::Linux::heap_dict_free_t os::Linux::_heap_dict_free;
+os::Linux::heap_vector_add_t os::Linux::_heap_vector_add;
+os::Linux::heap_vector_get_next_t os::Linux::_heap_vector_get_next;
+os::Linux::heap_vector_free_t os::Linux::_heap_vector_free;
void os::Linux::load_plugin_library() {
@@ -4595,6 +4601,12 @@ void os::Linux::load_plugin_library() {
_jboltLog_do = CAST_TO_FN_PTR(jboltLog_do_t, dlsym(RTLD_DEFAULT, "JBoltLog_DO"));
_jboltMerge_judge = CAST_TO_FN_PTR(jboltMerge_judge_t, dlsym(RTLD_DEFAULT, "JBoltMerge_Judge"));
#endif // INCLUDE_JBOLT
+ _heap_dict_add = CAST_TO_FN_PTR(heap_dict_add_t, dlsym(RTLD_DEFAULT, "HeapDict_Add"));
+ _heap_dict_lookup = CAST_TO_FN_PTR(heap_dict_lookup_t, dlsym(RTLD_DEFAULT, "HeapDict_Lookup"));
+ _heap_dict_free = CAST_TO_FN_PTR(heap_dict_free_t, dlsym(RTLD_DEFAULT, "HeapDict_Free"));
+ _heap_vector_add = CAST_TO_FN_PTR(heap_vector_add_t, dlsym(RTLD_DEFAULT, "HeapVector_Add"));
+ _heap_vector_get_next = CAST_TO_FN_PTR(heap_vector_get_next_t, dlsym(RTLD_DEFAULT, "HeapVector_GetNext"));
+ _heap_vector_free= CAST_TO_FN_PTR(heap_vector_free_t, dlsym(RTLD_DEFAULT, "HeapVector_Free"));
char path[JVM_MAXPATHLEN];
char ebuf[1024];
@@ -4612,12 +4624,31 @@ void os::Linux::load_plugin_library() {
_jboltLog_do = CAST_TO_FN_PTR(jboltLog_do_t, dlsym(handle, "JBoltLog_DO"));
}
if (_jboltMerge_judge == NULL) {
- _jboltMerge_judge = CAST_TO_FN_PTR(jboltMerge_judge_t, dlsym(handle, "JBoltMerge_Judge"));
+ _jboltMerge_judge = CAST_TO_FN_PTR(jboltMerge_judge_t, dlsym(handle, "JBoltMerge_Judge"));
}
#endif // INCLUDE_JBOLT
+
+ if(_heap_dict_add == NULL) {
+ _heap_dict_add = CAST_TO_FN_PTR(heap_dict_add_t, dlsym(handle, "HeapDict_Add"));
+ }
+ if(_heap_dict_lookup == NULL) {
+ _heap_dict_lookup = CAST_TO_FN_PTR(heap_dict_lookup_t, dlsym(handle, "HeapDict_Lookup"));
+ }
+ if(_heap_dict_free == NULL) {
+ _heap_dict_free = CAST_TO_FN_PTR(heap_dict_free_t, dlsym(handle, "HeapDict_Free"));
+ }
+ if(_heap_vector_add == NULL) {
+ _heap_vector_add = CAST_TO_FN_PTR(heap_vector_add_t, dlsym(handle, "HeapVector_Add"));
+ }
+ if(_heap_vector_get_next == NULL) {
+ _heap_vector_get_next = CAST_TO_FN_PTR(heap_vector_get_next_t, dlsym(handle, "HeapVector_GetNext"));
+ }
+ if(_heap_vector_free == NULL) {
+ _heap_vector_free= CAST_TO_FN_PTR(heap_vector_free_t, dlsym(handle, "HeapVector_Free"));
+ }
}
- JBOLT_ONLY(log_debug(jbolt)("Plugin library for JBolt: %s %s %s", BOOL_TO_STR(_jboltLog_precalc != nullptr),
+ JBOLT_ONLY(log_debug(jbolt)("Plugin library for JBolt: %s %s %s", BOOL_TO_STR(_jboltLog_precalc != nullptr),
BOOL_TO_STR(_jboltLog_do != nullptr),
BOOL_TO_STR(_jboltMerge_judge != nullptr));)
}
@@ -4747,6 +4778,8 @@ jint os::init_2(void) {
init_adjust_stacksize_for_guard_pages();
#endif
+ Linux::load_plugin_library();
+
if (UseNUMA || UseNUMAInterleaving) {
Linux::numa_init();
}
diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp
index 4192c90bd..871581f58 100644
--- a/src/hotspot/os/linux/os_linux.hpp
+++ b/src/hotspot/os/linux/os_linux.hpp
@@ -223,6 +223,20 @@ class os::Linux {
static jboltLog_do_t _jboltLog_do;
static jboltMerge_judge_t _jboltMerge_judge;
#endif
+
+ typedef void* (*heap_dict_add_t)(void* key, void* val, void* heap_dict, uint8_t type);
+ typedef void* (*heap_dict_lookup_t)(void* key, void* heap_dict, bool deletable);
+ typedef void (*heap_dict_free_t)(void* heap_dict, bool is_nested);
+ typedef void* (*heap_vector_add_t)(void* val, void* heap_vector, bool &_inserted);
+ typedef void* (*heap_vector_get_next_t)(void* heap_vector, void* heap_vector_node, int &_cnt, void** &_items);
+ typedef void (*heap_vector_free_t)(void* heap_vector);
+ static heap_dict_add_t _heap_dict_add;
+ static heap_dict_lookup_t _heap_dict_lookup;
+ static heap_dict_free_t _heap_dict_free;
+ static heap_vector_add_t _heap_vector_add;
+ static heap_vector_get_next_t _heap_vector_get_next;
+ static heap_vector_free_t _heap_vector_free;
+
static sched_getcpu_func_t _sched_getcpu;
static numa_node_to_cpus_func_t _numa_node_to_cpus;
static numa_node_to_cpus_v2_func_t _numa_node_to_cpus_v2;
@@ -459,6 +473,46 @@ class os::Linux {
return -1;
}
#endif // INCLUDE_JBOLT
+
+ static void* heap_dict_add(void* key, void* val, void* heap_dict, uint8_t type) {
+ if(_heap_dict_add == NULL) {
+ return NULL;
+ }
+ return _heap_dict_add(key, val, heap_dict, type);
+ }
+
+ static void* heap_dict_lookup(void* key, void* heap_dict, bool deletable) {
+ if(_heap_dict_lookup == NULL) {
+ return NULL;
+ }
+ return _heap_dict_lookup(key, heap_dict, deletable);
+ };
+
+ static void heap_dict_free(void* heap_dict, bool is_nested) {
+ if(_heap_dict_free != NULL) {
+ _heap_dict_free(heap_dict, is_nested);
+ }
+ }
+
+ static void* heap_vector_add(void* val, void* heap_vector, bool &_inserted) {
+ if(_heap_vector_add == NULL) {
+ return NULL;
+ }
+ return _heap_vector_add(val, heap_vector, _inserted);
+ }
+
+ static void* heap_vector_get_next(void* heap_vector, void* heap_vector_node, int &_cnt, void** &_items) {
+ if(_heap_vector_get_next == NULL) {
+ return NULL;
+ }
+ return _heap_vector_get_next(heap_vector, heap_vector_node, _cnt, _items);
+ }
+
+ static void heap_vector_free(void* heap_vector) {
+ if(_heap_vector_free != NULL) {
+ _heap_vector_free(heap_vector);
+ }
+ }
};
#endif // OS_LINUX_OS_LINUX_HPP
diff --git a/src/hotspot/share/oops/annotations.hpp b/src/hotspot/share/oops/annotations.hpp
index c7919ff0f..0260de2d8 100644
--- a/src/hotspot/share/oops/annotations.hpp
+++ b/src/hotspot/share/oops/annotations.hpp
@@ -41,6 +41,7 @@ typedef Array<u1> AnnotationArray;
// a type_annotation instance.
class Annotations: public MetaspaceObj {
+ friend class VMStructs;
friend class JVMCIVMStructs;
// If you add a new field that points to any metaspace object, you
diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp
index 2e2a9a0f2..dd053e458 100644
--- a/src/hotspot/share/runtime/arguments.cpp
+++ b/src/hotspot/share/runtime/arguments.cpp
@@ -58,6 +58,7 @@
#include "runtime/vm_version.hpp"
#include "services/management.hpp"
#include "services/nmtCommon.hpp"
+#include "services/heapRedactor.hpp"
#include "utilities/align.hpp"
#include "utilities/debug.hpp"
#include "utilities/defaultStream.hpp"
@@ -3691,6 +3692,29 @@ jint Arguments::match_special_option_and_act(const JavaVMInitArgs* args,
vm_exit(0);
}
+ if (match_option(option, "-XX:HeapDumpRedact", &tail)) {
+ // HeapDumpRedact arguments.
+ if (!HeapRedactor::check_launcher_heapdump_redact_support(tail)) {
+ warning("Heap dump redacting did not setup properly, using wrong argument?");
+ vm_exit_during_initialization("Syntax error, expecting -XX:HeapDumpRedact=[off|names|basic|full|diyrules|annotation]",NULL);
+ }
+ continue;
+ }
+
+ // heapDump redact password
+ if(match_option(option, "-XX:RedactPassword=", &tail)) {
+ if(tail == NULL || strlen(tail) == 0) {
+ VerifyRedactPassword = false;
+ } else {
+ char* split_char = strstr(const_cast<char*>(tail), ",");
+ VerifyRedactPassword = !(split_char == NULL || strlen(split_char) < SALT_LEN);
+ }
+ if(!VerifyRedactPassword) {
+ jio_fprintf(defaultStream::output_stream(), "redact password is null or with bad format, disable verify heap dump authority.\n");
+ }
+ }
+
+
#ifndef PRODUCT
if (match_option(option, "-XX:+PrintFlagsWithComments")) {
JVMFlag::printFlags(tty, true);
diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp
index 231c2ef16..5c028a21d 100644
--- a/src/hotspot/share/runtime/globals.hpp
+++ b/src/hotspot/share/runtime/globals.hpp
@@ -565,6 +565,24 @@ const int ObjectAlignmentInBytes = 8;
"compression. Otherwise the level must be between 1 and 9.") \
range(0, 9) \
\
+ product(ccstr, HeapDumpRedact, NULL, MANAGEABLE, \
+ "Redact the heapdump information to remove sensitive data") \
+ \
+ product(ccstr, RedactMap, NULL, MANAGEABLE, \
+ "Redact the class and field names to other strings") \
+ \
+ product(ccstr, RedactMapFile, NULL, MANAGEABLE, \
+ "File path of the Redact Map") \
+ \
+ product(ccstr, RedactClassPath, NULL, MANAGEABLE, \
+ "full path of the Redact Annotation") \
+ \
+ product(bool, VerifyRedactPassword, false, \
+ "verify authority for operating heapDump redact feature") \
+ \
+ product(ccstr, RedactPassword, NULL, \
+ "authority for operating heapDump redact feature, format {password,salt}, salt length >= 8") \
+ \
product(ccstr, NativeMemoryTracking, DEBUG_ONLY("summary") NOT_DEBUG("off"), \
"Native memory tracking options") \
\
diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp
index 827cb0cdf..15b1102cb 100644
--- a/src/hotspot/share/runtime/vmStructs.cpp
+++ b/src/hotspot/share/runtime/vmStructs.cpp
@@ -325,7 +325,11 @@
nonstatic_field(Symbol, _body[0], u1) \
nonstatic_field(TypeArrayKlass, _max_length, jint) \
nonstatic_field(OopHandle, _obj, oop*) \
- \
+ nonstatic_field(Annotations, _class_annotations, Array<u1>*) \
+ nonstatic_field(Annotations, _class_type_annotations, Array<u1>*) \
+ nonstatic_field(Annotations, _fields_annotations, Array<Array<u1>*>*) \
+ nonstatic_field(Annotations, _fields_type_annotations, Array<Array<u1>*>*) \
+ \
/***********************/ \
/* Constant Pool Cache */ \
/***********************/ \
@@ -477,6 +481,8 @@
nonstatic_field(Array<Klass*>, _data[0], Klass*) \
nonstatic_field(Array<ResolvedIndyEntry>, _length, int) \
nonstatic_field(Array<ResolvedIndyEntry>, _data[0], ResolvedIndyEntry) \
+ nonstatic_field(Array<Array<u1>*>, _length, int) \
+ nonstatic_field(Array<Array<u1>*>, _data[0], Array<u1>*) \
\
/*******************/ \
/* GrowableArrays */ \
@@ -1032,6 +1038,7 @@
unchecked_nonstatic_field(Array<Method*>, _data, sizeof(Method*)) \
unchecked_nonstatic_field(Array<Klass*>, _data, sizeof(Klass*)) \
unchecked_nonstatic_field(Array<ResolvedIndyEntry>, _data, sizeof(ResolvedIndyEntry)) \
+ unchecked_nonstatic_field(Array<Array<u1>*>, _data, sizeof(Array<u1>*)) \
\
/*********************************/ \
/* java_lang_Class fields */ \
@@ -1238,6 +1245,7 @@
declare_type(Method, Metadata) \
declare_type(MethodCounters, MetaspaceObj) \
declare_type(ConstMethod, MetaspaceObj) \
+ declare_type(Annotations, MetaspaceObj) \
\
declare_toplevel_type(MethodData::CompilerCounters) \
\
@@ -1960,6 +1969,7 @@
declare_type(Array<u2>, MetaspaceObj) \
declare_type(Array<Klass*>, MetaspaceObj) \
declare_type(Array<Method*>, MetaspaceObj) \
+ declare_type(Array<Array<u1>*>, MetaspaceObj) \
declare_type(Array<ResolvedIndyEntry>, MetaspaceObj) \
\
declare_toplevel_type(BitMap) \
diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp
index b426f5d4c..82e721c17 100644
--- a/src/hotspot/share/services/heapDumper.cpp
+++ b/src/hotspot/share/services/heapDumper.cpp
@@ -54,11 +54,13 @@
#include "runtime/vframe.hpp"
#include "runtime/vmOperations.hpp"
#include "runtime/vmThread.hpp"
+#include "runtime/fieldDescriptor.inline.hpp"
#include "services/heapDumper.hpp"
#include "services/heapDumperCompression.hpp"
#include "services/threadService.hpp"
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
+#include "services/heapRedactor.hpp"
/*
* HPROF binary format - description copied from:
@@ -413,6 +415,8 @@ class AbstractDumpWriter : public StackObj {
void write_address(address a);
+ HeapRedactor* redactor;
+
public:
AbstractDumpWriter() :
_buffer(nullptr),
@@ -427,6 +431,7 @@ class AbstractDumpWriter : public StackObj {
size_t position() const { return _pos; }
// writer functions
virtual void write_raw(const void* s, size_t len);
+ void write_zero_raw(void* s, size_t len);
void write_u1(u1 x);
void write_u2(u2 x);
void write_u4(u4 x);
@@ -452,6 +457,12 @@ class AbstractDumpWriter : public StackObj {
// Force flush to guarantee data from parallel dumper are written.
flush(true);
}
+
+ // remove sensitive data from heapdump information
+ void setHeapRedactor(HeapRedactor* value);
+ HeapRedactor* heapRedactor();
+ HeapDumpRedactLevel getHeapDumpRedactLevel();
+
// Called when finished to release the threads.
virtual void deactivate() = 0;
};
@@ -489,6 +500,27 @@ void AbstractDumpWriter::write_raw(const void* s, size_t len) {
set_position(position() + len);
}
+void AbstractDumpWriter::write_zero_raw(void* s, size_t len) {
+ assert(!_in_dump_segment || (_sub_record_left >= len), "sub-record too large");
+ debug_only(_sub_record_left -= len);
+
+ // flush buffer to make room.
+ while (len > buffer_size() - position()) {
+ assert(!_in_dump_segment || _is_huge_sub_record,
+ "Cannot overflow in non-huge sub-record.");
+
+ size_t to_write = buffer_size() - position();
+ memset(buffer() + position(), 0, to_write);
+ s = (void*) ((char*) s + to_write);
+ len -= to_write;
+ set_position(position() + to_write);
+ flush();
+ }
+
+ memset(buffer() + position(), 0, len);
+ set_position(position() + len);
+}
+
// Makes sure we inline the fast write into the write_u* functions. This is a big speedup.
#define WRITE_KNOWN_TYPE(p, len) do { if (can_write_fast((len))) write_fast((p), (len)); \
else write_raw((p), (len)); } while (0)
@@ -608,6 +640,21 @@ void AbstractDumpWriter::end_sub_record() {
debug_only(_sub_record_ended = true);
}
+void AbstractDumpWriter::setHeapRedactor(HeapRedactor* value) {
+ redactor = value;
+}
+
+HeapRedactor* AbstractDumpWriter::heapRedactor() {
+ return redactor;
+}
+
+HeapDumpRedactLevel AbstractDumpWriter::getHeapDumpRedactLevel() {
+ if(redactor==NULL){
+ return REDACT_OFF;
+ }
+ return redactor->redact_level();
+}
+
// Supports I/O operations for a dump
class DumpWriter : public AbstractDumpWriter {
@@ -886,6 +933,9 @@ Monitor* ParDumpWriter::_lock = nullptr;
class DumperClassCacheTable;
class DumperClassCacheTableEntry;
+typedef char* (*CALL_DO_LOOKUP_REPLACE_VALUE)(AbstractDumpWriter*, typeArrayOop);
+typedef void (*CALL_DUMP_INSTANCE_FIELDS_DESCRIPTORS)(AbstractDumpWriter*, Klass*);
+typedef void (*CALL_DUMP_PRIM_ARRAY)(AbstractDumpWriter*, typeArrayOop);
// Support class with a collection of functions used when dumping the heap
class DumperSupport : AllStatic {
public:
@@ -915,14 +965,26 @@ class DumperSupport : AllStatic {
static void dump_static_fields(AbstractDumpWriter* writer, Klass* k);
// dump the raw values of the instance fields of the given object
static void dump_instance_fields(AbstractDumpWriter* writer, oop o, DumperClassCacheTableEntry* class_cache_entry);
+ // dump the redact values of the instance fields of the given object
+ static void dump_instance_redact_fields(AbstractDumpWriter* writer, oop o, DumperClassCacheTableEntry* class_cache_entry, void* replace_value_table, uint container_id);
// get the count of the instance fields for a given class
static u2 get_instance_fields_count(InstanceKlass* ik);
// dumps the definition of the instance fields for a given class
static void dump_instance_field_descriptors(AbstractDumpWriter* writer, Klass* k);
+ // dumps the definition of the instance fields for a given class
+ static void dump_instance_annotation_field_descriptors(AbstractDumpWriter* writer, Klass* k);
+ // dumps the definition of the instance fields for a given class
+ static void dump_instance_diyrules_field_descriptors(AbstractDumpWriter* writer, Klass* k);
// creates HPROF_GC_INSTANCE_DUMP record for the given object
static void dump_instance(AbstractDumpWriter* writer, oop o, DumperClassCacheTable* class_cache);
+ // creates HPROF_GC_INSTANCE_REDACT_DUMP record for the given object
+ static void dump_redact_instance(AbstractDumpWriter* writer, oop o, DumperClassCacheTable* class_cache, uint container_id);
+ // lookup different value type depend on redact mode
+ static char* do_lookup_replace_value_with_symbol(AbstractDumpWriter* writer, typeArrayOop array);
+ static char* do_lookup_replace_value_with_char(AbstractDumpWriter* writer, typeArrayOop array);
+ static bool dump_replace_value(CALL_DO_LOOKUP_REPLACE_VALUE fn, AbstractDumpWriter* writer, typeArrayOop array, uint container_id);
// creates HPROF_GC_CLASS_DUMP record for the given instance class
- static void dump_instance_class(AbstractDumpWriter* writer, Klass* k);
+ static void dump_instance_class(CALL_DUMP_INSTANCE_FIELDS_DESCRIPTORS fn, AbstractDumpWriter* writer, Klass* k);
// creates HPROF_GC_CLASS_DUMP record for a given array class
static void dump_array_class(AbstractDumpWriter* writer, Klass* k);
@@ -930,15 +992,22 @@ class DumperSupport : AllStatic {
static void dump_object_array(AbstractDumpWriter* writer, objArrayOop array);
// creates HPROF_GC_PRIM_ARRAY_DUMP record for the given type array
static void dump_prim_array(AbstractDumpWriter* writer, typeArrayOop array);
+ // creates HPROF_GC_PRIM_ARRAY_REDACT_DUMP record for the given type array
+ static void redact_basic_dump_prim_array(AbstractDumpWriter* writer, typeArrayOop array);
+ static void redact_replace_dump_prim_array(CALL_DO_LOOKUP_REPLACE_VALUE fn, AbstractDumpWriter* writer, typeArrayOop array, uint container_id);
+ static void redact_dump_prim_array(CALL_DUMP_PRIM_ARRAY fn, AbstractDumpWriter* dumpWriter, typeArrayOop o);
// create HPROF_FRAME record for the given method and bci
static void dump_stack_frame(AbstractDumpWriter* writer, int frame_serial_num, int class_serial_num, Method* m, int bci);
// check if we need to truncate an array
- static int calculate_array_max_length(AbstractDumpWriter* writer, arrayOop array, short header_size);
+ static int calculate_array_max_length(AbstractDumpWriter* writer, arrayOop array, short header_size, int char_length = 0);
// fixes up the current dump record and writes HPROF_HEAP_DUMP_END record
static void end_of_dump(AbstractDumpWriter* writer);
+ // is_large function, if oop is large object, retrun true
+ static bool is_large(oop o);
+
static oop mask_dormant_archived_object(oop o, oop ref_obj) {
if (o != nullptr && o->klass()->java_mirror_no_keepalive() == nullptr) {
// Ignore this object since the corresponding java mirror is not loaded.
@@ -974,6 +1043,7 @@ class DumperClassCacheTableEntry : public CHeapObj<mtServiceability> {
private:
GrowableArray<char> _sigs_start;
GrowableArray<int> _offsets;
+ GrowableArray<address> _name_symbol_addrs;
u4 _instance_size;
int _entries;
@@ -983,6 +1053,7 @@ public:
int field_count() { return _entries; }
char sig_start(int field_idx) { return _sigs_start.at(field_idx); }
int offset(int field_idx) { return _offsets.at(field_idx); }
+ address name_symbol_addrs(int field_idx) { return _name_symbol_addrs.at(field_idx); }
u4 instance_size() { return _instance_size; }
};
@@ -1033,6 +1104,7 @@ public:
Symbol* sig = fld.signature();
entry->_sigs_start.push(sig->char_at(0));
entry->_offsets.push(fld.offset());
+ entry->_name_symbol_addrs.push((address)((uintptr_t)fld.name()));
entry->_entries++;
entry->_instance_size += DumperSupport::sig2size(sig);
}
@@ -1309,6 +1381,37 @@ void DumperSupport::dump_instance_fields(AbstractDumpWriter* writer, oop o, Dump
}
}
+// dump the diyrules values of the instance fields of the given object
+void DumperSupport::dump_instance_redact_fields(AbstractDumpWriter* writer, oop o, DumperClassCacheTableEntry* class_cache_entry, void* replace_value_table, uint container_id) {
+ InstanceKlass* ik = InstanceKlass::cast(o->klass());
+
+ for (int idx = 0; idx < class_cache_entry->field_count(); idx++) {
+
+ char type = class_cache_entry->sig_start(idx);
+ int offset = class_cache_entry->offset(idx);
+
+ ResourceMark rm;
+ address field_adr = class_cache_entry->name_symbol_addrs(idx);
+ void* replace_value = writer->heapRedactor()->lookup_value(field_adr, replace_value_table, false);
+
+ if (replace_value != nullptr) {
+ oop field_oop = o->obj_field_access<ON_UNKNOWN_OOP_REF | AS_NO_KEEPALIVE>(offset);
+ if (!java_lang_String::is_instance(field_oop)) {
+ // data not completed, skip this field value;
+ writer->write_objectID(nullptr);
+ continue;
+ }
+
+ typeArrayOop field_value_oop = java_lang_String::value(field_oop);
+ address type_array_addr = cast_from_oop<address>(field_value_oop);
+ writer->heapRedactor()->insert_anonymous_value(type_array_addr, replace_value, container_id);
+ writer->write_objectID(field_oop);
+ continue;
+ }
+ dump_field_value(writer, type, o, offset);
+ }
+}
+
// dumps the definition of the instance fields for a given class
u2 DumperSupport::get_instance_fields_count(InstanceKlass* ik) {
u2 field_count = 0;
@@ -1335,6 +1438,97 @@ void DumperSupport::dump_instance_field_descriptors(AbstractDumpWriter* writer,
}
}
+// dumps the definition of the instance fields for a given class
+void DumperSupport::dump_instance_annotation_field_descriptors(AbstractDumpWriter* writer, Klass* k) {
+ ResourceMark rm;
+ InstanceKlass* ik = InstanceKlass::cast(k);
+ Symbol *class_name_symbol = ik->name();
+ bool in_exclude_package = false;
+ if (Symbol::is_valid(class_name_symbol)) {
+ char *class_name = class_name_symbol->as_C_string();
+ in_exclude_package = (strncmp("java/", class_name, 5) == 0) || (strncmp("org/springframework", class_name, 19) == 0);
+ }
+
+ if(in_exclude_package) {
+ DumperSupport::dump_instance_field_descriptors(writer, k);
+ return;
+ }
+
+ address obj_adr = (address)((uintptr_t)class_name_symbol);
+ // dump the field descriptors
+ for (JavaFieldStream fld(ik); !fld.done(); fld.next()) {
+ if (!fld.access_flags().is_static()) {
+ Symbol* sig = fld.signature();
+ Symbol* field_name = fld.name();
+
+ writer->write_symbolID(field_name); // name
+ writer->write_u1(sig2tag(sig)); // type
+
+ if(strcmp(sig->as_C_string(), "Ljava/lang/String;") != 0) {
+ continue;
+ }
+
+ AnnotationArray *field_annotations = fld.field_descriptor().annotations();
+ if (field_annotations == nullptr || field_annotations->length() == 0) {
+ continue;
+ }
+
+ // byte index into field_annotations
+ ConstantPool *cp = fld.field_descriptor().field_holder()->constants();
+ int byte_i = 0;
+ if (writer->heapRedactor()->lookup_annotation_index_in_constant_pool(field_annotations, cp, byte_i)) {
+ address element_value_addr = (address) field_annotations->adr_at(byte_i);
+ u2 cp_str_index = Bytes::get_Java_u2(element_value_addr);
+ Symbol *element_value_symbol = cp->symbol_at(cp_str_index);
+
+ address field_adr = (address) ((uintptr_t) field_name);
+ writer->heapRedactor()->insert_class_field_value(obj_adr, field_adr, element_value_symbol);
+ }
+ }
+ }
+}
+
+// dumps the definition of the instance fields for a given class
+void DumperSupport::dump_instance_diyrules_field_descriptors(AbstractDumpWriter *writer, Klass *k) {
+ ResourceMark rm;
+ InstanceKlass* ik = InstanceKlass::cast(k);
+ Symbol *class_name_symbol = ik->name();
+ void* redact_class_table = nullptr;
+ bool has_diyrules = false;
+ if (Symbol::is_valid(class_name_symbol)) {
+ char *class_name = class_name_symbol->as_C_string();
+ redact_class_table = writer->heapRedactor()->lookup_class_rules(class_name);
+ has_diyrules = (redact_class_table != nullptr);
+ }
+
+ if (!has_diyrules) {
+ DumperSupport::dump_instance_field_descriptors(writer, k);
+ return;
+ }
+
+ address obj_adr = (address) ((uintptr_t) class_name_symbol);
+ // dump the field descriptors
+ for (JavaFieldStream fld(ik); !fld.done(); fld.next()) {
+ if (!fld.access_flags().is_static()) {
+ Symbol* sig = fld.signature();
+ Symbol* field_name = fld.name();
+
+ writer->write_symbolID(field_name); // name
+ writer->write_u1(sig2tag(sig)); // type
+
+ if(strcmp(sig->as_C_string(), "Ljava/lang/String;") != 0) {
+ continue;
+ }
+ char *field_name_str = field_name->as_C_string();
+ char *replace_value = (char *) writer->heapRedactor()->lookup_value(field_name_str, redact_class_table, false);
+ if (replace_value != nullptr) {
+ address field_adr = (address) ((uintptr_t) field_name);
+ writer->heapRedactor()->insert_class_field_value(obj_adr, field_adr, replace_value);
+ }
+ }
+ }
+}
+
// creates HPROF_GC_INSTANCE_DUMP record for the given object
void DumperSupport::dump_instance(AbstractDumpWriter* writer, oop o, DumperClassCacheTable* class_cache) {
InstanceKlass* ik = InstanceKlass::cast(o->klass());
@@ -1360,8 +1554,104 @@ void DumperSupport::dump_instance(AbstractDumpWriter* writer, oop o, DumperClass
writer->end_sub_record();
}
+// creates HPROF_GC_INSTANCE_REDACT_DUMP record for the given object
+void DumperSupport::dump_redact_instance(AbstractDumpWriter* writer, oop o, DumperClassCacheTable* class_cache, uint container_id) {
+ InstanceKlass* ik = InstanceKlass::cast(o->klass());
+
+ DumperClassCacheTableEntry* cache_entry = class_cache->lookup_or_create(ik);
+
+ u4 is = instance_size(ik);
+ u4 size = 1 + sizeof(address) + 4 + sizeof(address) + 4 + is;
+
+ writer->start_sub_record(HPROF_GC_INSTANCE_DUMP, size);
+ writer->write_objectID(o);
+ writer->write_u4(STACK_TRACE_ID);
+
+ // class ID
+ writer->write_classID(ik);
+
+ // number of bytes that follow
+ writer->write_u4(is);
+
+ // field values
+ void* replace_value_table = nullptr;
+ InstanceKlass* java_super = ik;
+ do {
+ Symbol * class_name_symbol = java_super->name();
+ address obj_adr = (address)((uintptr_t)class_name_symbol);
+ replace_value_table = writer->heapRedactor()->lookup_class_value(obj_adr);
+ java_super = java_super->java_super();
+ } while (replace_value_table == nullptr && java_super != nullptr);
+
+ bool has_rules = replace_value_table != nullptr;
+ if(has_rules) {
+ dump_instance_redact_fields(writer, o, cache_entry, replace_value_table, container_id);
+ } else {
+ dump_instance_fields(writer, o, cache_entry);
+ }
+
+ writer->end_sub_record();
+}
+
+char* DumperSupport::do_lookup_replace_value_with_symbol(AbstractDumpWriter* writer, typeArrayOop array) {
+ address obj_addr = cast_from_oop<address>(array);
+ Symbol* anonymous_value_symbol = writer->heapRedactor()->lookup_replace_value<Symbol*>(obj_addr);
+ if(anonymous_value_symbol == nullptr) {
+ return nullptr;
+ }
+ return anonymous_value_symbol->as_C_string();
+}
+
+char* DumperSupport::do_lookup_replace_value_with_char(AbstractDumpWriter* writer, typeArrayOop array) {
+ address obj_addr = cast_from_oop<address>(array);
+ char* anonymous_value = writer->heapRedactor()->lookup_replace_value<char*>(obj_addr);
+ return anonymous_value;
+}
+
+bool DumperSupport::dump_replace_value(CALL_DO_LOOKUP_REPLACE_VALUE fn, AbstractDumpWriter* writer, typeArrayOop array, uint container_id) {
+ BasicType type = TypeArrayKlass::cast(array->klass())->element_type();
+ if(type != T_BYTE) {
+ return false;
+ }
+
+ // 2 * sizeof(u1) + 2 * sizeof(u4) + sizeof(objectID)
+ short header_size = 2 * 1 + 2 * 4 + sizeof(address);
+
+ int length = 0;
+
+ char *anonymous_value = nullptr;
+ anonymous_value = fn(writer, array);
+ if(anonymous_value == nullptr) {
+ // record all array, expect who's replace value can be find now
+ return writer->heapRedactor()->record_typeArrayOop(array, container_id);
+ }
+
+ size_t char_length = strlen(anonymous_value);
+ length = DumperSupport::calculate_array_max_length(writer, array, header_size, char_length);
+
+ int type_size = type2aelembytes(type);
+ u4 length_in_bytes = (u4)length * type_size;
+ u4 size = header_size + length_in_bytes;
+
+ writer->start_sub_record(HPROF_GC_PRIM_ARRAY_DUMP, size);
+ writer->write_objectID(array);
+ writer->write_u4(STACK_TRACE_ID);
+ writer->write_u4(length);
+ writer->write_u1(HPROF_BYTE);
+
+ // nothing to copy
+ if (length == 0) {
+ writer->end_sub_record();
+ return true;
+ }
+
+ writer->write_raw(anonymous_value, char_length);
+ writer->end_sub_record();
+ return true;
+}
+
// creates HPROF_GC_CLASS_DUMP record for the given instance class
-void DumperSupport::dump_instance_class(AbstractDumpWriter* writer, Klass* k) {
+void DumperSupport::dump_instance_class(CALL_DUMP_INSTANCE_FIELDS_DESCRIPTORS fn, AbstractDumpWriter* writer, Klass* k) {
InstanceKlass* ik = InstanceKlass::cast(k);
// We can safepoint and do a heap dump at a point where we have a Klass,
@@ -1411,7 +1701,7 @@ void DumperSupport::dump_instance_class(AbstractDumpWriter* writer, Klass* k) {
// description of instance fields
writer->write_u2(instance_fields_count);
- dump_instance_field_descriptors(writer, ik);
+ fn(writer, ik);
writer->end_sub_record();
}
@@ -1454,12 +1744,11 @@ void DumperSupport::dump_array_class(AbstractDumpWriter* writer, Klass* k) {
// Hprof uses an u4 as record length field,
// which means we need to truncate arrays that are too long.
-int DumperSupport::calculate_array_max_length(AbstractDumpWriter* writer, arrayOop array, short header_size) {
+int DumperSupport::calculate_array_max_length(AbstractDumpWriter* writer, arrayOop array, short header_size, int char_length) {
BasicType type = ArrayKlass::cast(array->klass())->element_type();
assert(type >= T_BOOLEAN && type <= T_OBJECT, "invalid array element type");
- int length = array->length();
-
+ int length = char_length == 0 ? array->length() : char_length;
int type_size;
if (type == T_OBJECT) {
type_size = sizeof(address);
@@ -1543,7 +1832,7 @@ void DumperSupport::dump_prim_array(AbstractDumpWriter* writer, typeArrayOop arr
break;
}
case T_BYTE : {
- writer->write_raw(array->byte_at_addr(0), length_in_bytes);
+ writer->write_raw((void*)(array->byte_at_addr(0)), length_in_bytes);
break;
}
case T_CHAR : {
@@ -1601,6 +1890,101 @@ void DumperSupport::dump_prim_array(AbstractDumpWriter* writer, typeArrayOop arr
writer->end_sub_record();
}
+// creates HPROF_GC_PRIM_ARRAY_DUMP redact record for the given type array
+void DumperSupport::redact_basic_dump_prim_array(AbstractDumpWriter* writer, typeArrayOop array) {
+ BasicType type = TypeArrayKlass::cast(array->klass())->element_type();
+
+ // 2 * sizeof(u1) + 2 * sizeof(u4) + sizeof(objectID)
+ short header_size = 2 * 1 + 2 * 4 + sizeof(address);
+
+ int length = calculate_array_max_length(writer, array, header_size);
+ int type_size = type2aelembytes(type);
+ u4 length_in_bytes = (u4)length * type_size;
+ u4 size = header_size + length_in_bytes;
+
+ writer->start_sub_record(HPROF_GC_PRIM_ARRAY_DUMP, size);
+ writer->write_objectID(array);
+ writer->write_u4(STACK_TRACE_ID);
+ writer->write_u4(length);
+ writer->write_u1(type2tag(type));
+
+ // nothing to copy
+ if (length == 0) {
+ writer->end_sub_record();
+ return;
+ }
+
+ // If the byte ordering is big endian then we can copy most types directly
+
+ switch (type) {
+ case T_INT : {
+ writer->write_zero_raw((void*)(array->int_at_addr(0)), length_in_bytes);
+ break;
+ }
+ case T_BYTE : {
+ writer->write_zero_raw((void*)(array->byte_at_addr(0)), length_in_bytes);
+ break;
+ }
+ case T_CHAR : {
+ writer->write_zero_raw((void*)(array->char_at_addr(0)), length_in_bytes);
+ break;
+ }
+ case T_SHORT : {
+ if (Endian::is_Java_byte_ordering_different()) {
+ WRITE_ARRAY(array, short, u2, length);
+ } else {
+ writer->write_raw((void*)(array->short_at_addr(0)), length_in_bytes);
+ }
+ break;
+ }
+ case T_BOOLEAN : {
+ if (Endian::is_Java_byte_ordering_different()) {
+ WRITE_ARRAY(array, bool, u1, length);
+ } else {
+ writer->write_raw((void*)(array->bool_at_addr(0)), length_in_bytes);
+ }
+ break;
+ }
+ case T_LONG : {
+ if (Endian::is_Java_byte_ordering_different()) {
+ WRITE_ARRAY(array, long, u8, length);
+ } else {
+ writer->write_raw((void*)(array->long_at_addr(0)), length_in_bytes);
+ }
+ break;
+ }
+
+ // handle float/doubles in a special value to ensure than NaNs are
+ // written correctly. TO DO: Check if we can avoid this on processors that
+ // use IEEE 754.
+
+ case T_FLOAT : {
+ for (int i = 0; i < length; i++) {
+ dump_float(writer, array->float_at(i));
+ }
+ break;
+ }
+ case T_DOUBLE : {
+ for (int i = 0; i < length; i++) {
+ dump_double(writer, array->double_at(i));
+ }
+ break;
+ }
+ default : ShouldNotReachHere();
+ }
+
+ writer->end_sub_record();
+}
+
+// creates HPROF_GC_PRIM_ARRAY_DUMP redact record for the given type array
+void DumperSupport::redact_replace_dump_prim_array(CALL_DO_LOOKUP_REPLACE_VALUE fn, AbstractDumpWriter *writer, typeArrayOop array, uint container_id) {
+ if(dump_replace_value(fn, writer, array, container_id)) {
+ return;
+ }
+
+ DumperSupport::dump_prim_array(writer, array);
+}
+
// create a HPROF_FRAME record of the given Method* and bci
void DumperSupport::dump_stack_frame(AbstractDumpWriter* writer,
int frame_serial_num,
@@ -1650,6 +2034,39 @@ void SymbolTableDumper::do_symbol(Symbol** p) {
}
}
+// Support class used to generate HPROF_UTF8 records from the entries in the
+// SymbolTable and Redact the sensitive String.
+
+class SymbolTableRedactDumper : public SymbolClosure {
+private:
+ AbstractDumpWriter* _writer;
+ AbstractDumpWriter* writer() const { return _writer; }
+public:
+ SymbolTableRedactDumper(AbstractDumpWriter* writer) { _writer = writer; }
+ void do_symbol(Symbol** p);
+};
+
+void SymbolTableRedactDumper::do_symbol(Symbol** p) {
+ ResourceMark rm;
+ Symbol* sym = *p;
+ int len = sym->utf8_length();
+ if (len > 0) {
+ char* s = sym->as_utf8();
+
+ char* redact_field = NULL;
+ HeapDumpRedactLevel level = writer()->getHeapDumpRedactLevel();
+ if((level == REDACT_NAMES || level == REDACT_FULL) &&
+ (redact_field = writer()->heapRedactor()->lookup_redact_name(s)) != NULL){
+ len = (int)strlen(redact_field);
+ s = redact_field;
+ }
+
+ DumperSupport::write_header(writer(), HPROF_UTF8, oopSize + len);
+ writer()->write_symbolID(sym);
+ writer()->write_raw(s, len);
+ }
+}
+
// Support class used to generate HPROF_GC_ROOT_JNI_LOCAL records
class JNILocalsDumper : public OopClosure {
@@ -1809,17 +2226,19 @@ class HeapObjectDumper : public ObjectClosure {
private:
AbstractDumpWriter* _writer;
HeapDumpLargeObjectList* _list;
+ CALL_DUMP_PRIM_ARRAY _redact_dump_prim_array;
AbstractDumpWriter* writer() { return _writer; }
- bool is_large(oop o);
+ // bool is_large(oop o);
DumperClassCacheTable _class_cache;
public:
- HeapObjectDumper(AbstractDumpWriter* writer, HeapDumpLargeObjectList* list = nullptr) {
- _writer = writer;
- _list = list;
- }
+ HeapObjectDumper(AbstractDumpWriter* writer, CALL_DUMP_PRIM_ARRAY fn = DumperSupport::dump_prim_array, HeapDumpLargeObjectList* list = nullptr) {
+ _writer = writer;
+ _list = list;
+ _redact_dump_prim_array = fn;
+ }
// called for each object in the heap
void do_object(oop o);
@@ -1839,7 +2258,7 @@ void HeapObjectDumper::do_object(oop o) {
// If large object list exists and it is large object/array,
// add oop into the list and skip scan. VM thread will process it later.
- if (_list != nullptr && is_large(o)) {
+ if (_list != nullptr && DumperSupport::is_large(o)) {
_list->atomic_push(o);
return;
}
@@ -1852,11 +2271,72 @@ void HeapObjectDumper::do_object(oop o) {
DumperSupport::dump_object_array(writer(), objArrayOop(o));
} else if (o->is_typeArray()) {
// create a HPROF_GC_PRIM_ARRAY_DUMP record for each type array
- DumperSupport::dump_prim_array(writer(), typeArrayOop(o));
+ DumperSupport::redact_dump_prim_array(_redact_dump_prim_array, writer(), typeArrayOop(o));
}
}
-bool HeapObjectDumper::is_large(oop o) {
+void DumperSupport::redact_dump_prim_array(CALL_DUMP_PRIM_ARRAY fn, AbstractDumpWriter* dumpWriter, typeArrayOop o){
+ fn(dumpWriter, o);
+}
+
+class HeapObjectRedactDumper : public ObjectClosure {
+private:
+ AbstractDumpWriter* _writer;
+ HeapDumpLargeObjectList* _list;
+
+ AbstractDumpWriter* writer() { return _writer; }
+
+ CALL_DO_LOOKUP_REPLACE_VALUE _do_lookup_replace_value;
+
+ DumperClassCacheTable _class_cache;
+
+ uint container_id;
+
+public:
+ HeapObjectRedactDumper(AbstractDumpWriter* writer, CALL_DO_LOOKUP_REPLACE_VALUE do_lookup_replace_value, HeapDumpLargeObjectList* list = nullptr, uint id = 0) {
+ _writer = writer;
+ _list = list;
+ container_id = id;
+ _do_lookup_replace_value = do_lookup_replace_value;
+ }
+
+ // called for each object in the heap
+ void do_object(oop o);
+};
+
+void HeapObjectRedactDumper::do_object(oop o) {
+ // skip classes as these emitted as HPROF_GC_CLASS_DUMP records
+ if (o->klass() == vmClasses::Class_klass()) {
+ if (!java_lang_Class::is_primitive(o)) {
+ return;
+ }
+ }
+
+ if (DumperSupport::mask_dormant_archived_object(o, nullptr) == nullptr) {
+ log_debug(cds, heap)("skipped dormant archived object " INTPTR_FORMAT " (%s)", p2i(o), o->klass()->external_name());
+ return;
+ }
+
+ // If large object list exists and it is large object/array,
+ // and oop into the list and skip scan. VM thread will process it later.
+ if (_list != nullptr && DumperSupport::is_large(o)) {
+ _list->atomic_push(o);
+ return;
+ }
+
+ if (o->is_instance()) {
+ // create a HPROF_GC_INSTANCE record for each object
+ DumperSupport::dump_redact_instance(writer(), o, &_class_cache, container_id);
+ } else if (o->is_objArray()) {
+ // create a HPROF_GC_OBJ_ARRAY_DUMP record for each object array
+ DumperSupport::dump_object_array(writer(), objArrayOop(o));
+ } else if (o->is_typeArray()) {
+ // create a HPROF_GC_PRIM_ARRAY_DUMP record for each type array
+ DumperSupport::redact_replace_dump_prim_array(_do_lookup_replace_value, writer(), typeArrayOop(o), container_id);
+ }
+}
+
+bool DumperSupport::is_large(oop o) {
size_t size = 0;
if (o->is_instance()) {
// Use o->size() * 8 as the upper limit of instance size to avoid iterating static fields
@@ -1941,6 +2421,7 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask {
ThreadStackTrace** _stack_traces;
int _num_threads;
// parallel heap dump support
+ static CALL_DUMP_INSTANCE_FIELDS_DESCRIPTORS _dump_instance_fields_descriptors;
uint _num_dumper_threads;
uint _num_writer_threads;
DumperController* _dumper_controller;
@@ -2033,6 +2514,9 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask {
// HPROF_TRACE and HPROF_FRAME records
void dump_stack_traces();
+ // HeapVector Records
+ void do_heapVector();
+
// large objects
void dump_large_objects(ObjectClosure* writer);
@@ -2052,6 +2536,14 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask {
_dumper_controller = nullptr;
_poi = nullptr;
_large_object_list = new (std::nothrow) HeapDumpLargeObjectList();
+ if(writer->getHeapDumpRedactLevel() == REDACT_ANNOTATION) {
+ _dump_instance_fields_descriptors = DumperSupport::dump_instance_annotation_field_descriptors;
+ } else if(writer->getHeapDumpRedactLevel() == REDACT_DIYRULES) {
+ _dump_instance_fields_descriptors = DumperSupport::dump_instance_diyrules_field_descriptors;
+ } else {
+ _dump_instance_fields_descriptors = DumperSupport::dump_instance_field_descriptors;
+ }
+
if (oome) {
assert(!Thread::current()->is_VM_thread(), "Dump from OutOfMemoryError cannot be called by the VMThread");
// get OutOfMemoryError zero-parameter constructor
@@ -2089,6 +2581,7 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask {
VM_HeapDumper* VM_HeapDumper::_global_dumper = nullptr;
DumpWriter* VM_HeapDumper::_global_writer = nullptr;
+CALL_DUMP_INSTANCE_FIELDS_DESCRIPTORS VM_HeapDumper::_dump_instance_fields_descriptors = nullptr;
bool VM_HeapDumper::skip_operation() const {
return false;
@@ -2131,8 +2624,8 @@ void VM_HeapDumper::do_load_class(Klass* k) {
// writes a HPROF_GC_CLASS_DUMP record for the given class
void VM_HeapDumper::do_class_dump(Klass* k) {
if (k->is_instance_klass()) {
- DumperSupport::dump_instance_class(writer(), k);
- } else {
+ DumperSupport::dump_instance_class(_dump_instance_fields_descriptors, writer(), k);
+ } else {
DumperSupport::dump_array_class(writer(), k);
}
}
@@ -2317,14 +2810,15 @@ void VM_HeapDumper::doit() {
set_global_writer();
WorkerThreads* workers = ch->safepoint_workers();
-
if (workers == nullptr) {
// Use serial dump, set dumper threads and writer threads number to 1.
_num_dumper_threads=1;
_num_writer_threads=1;
+ writer()->heapRedactor()->init_containers(_num_dumper_threads);
work(0);
} else {
prepare_parallel_dump(workers->active_workers());
+ writer()->heapRedactor()->init_containers(_num_dumper_threads);
if (_num_dumper_threads > 1) {
ParallelObjectIterator poi(_num_dumper_threads);
_poi = &poi;
@@ -2361,8 +2855,14 @@ void VM_HeapDumper::work(uint worker_id) {
// timestamp is current time in ms
writer()->write_u8(os::javaTimeMillis());
// HPROF_UTF8 records
- SymbolTableDumper sym_dumper(writer());
- SymbolTable::symbols_do(&sym_dumper);
+ if(writer()->heapRedactor() != NULL && (writer()->heapRedactor()->redact_level() == REDACT_NAMES ||
+ writer()->heapRedactor()->redact_level() == REDACT_FULL)){
+ SymbolTableRedactDumper sym_dumper(writer());
+ SymbolTable::symbols_do(&sym_dumper);
+ } else{
+ SymbolTableDumper sym_dumper(writer());
+ SymbolTable::symbols_do(&sym_dumper);
+ }
// write HPROF_LOAD_CLASS records
{
@@ -2403,8 +2903,20 @@ void VM_HeapDumper::work(uint worker_id) {
// of the heap dump.
if (_num_dumper_threads <= 1) {
ResourceMark rm;
- HeapObjectDumper obj_dumper(writer());
- Universe::heap()->object_iterate(&obj_dumper);
+ if(writer()->heapRedactor() != NULL && (writer()->heapRedactor()->redact_level() == REDACT_BASIC ||
+ writer()->heapRedactor()->redact_level() == REDACT_FULL)) {
+ HeapObjectDumper obj_dumper(writer(), DumperSupport::redact_basic_dump_prim_array);
+ Universe::heap()->object_iterate(&obj_dumper);
+ } else if(writer()->heapRedactor() != NULL && writer()->heapRedactor()->redact_level() == REDACT_ANNOTATION) {
+ HeapObjectRedactDumper obj_dumper(writer(), DumperSupport::do_lookup_replace_value_with_symbol);
+ Universe::heap()->object_iterate(&obj_dumper);
+ } else if(writer()->heapRedactor() != NULL && writer()->heapRedactor()->redact_level() == REDACT_DIYRULES) {
+ HeapObjectRedactDumper obj_dumper(writer(), DumperSupport::do_lookup_replace_value_with_char);
+ Universe::heap()->object_iterate(&obj_dumper);
+ } else {
+ HeapObjectDumper obj_dumper(writer());
+ Universe::heap()->object_iterate(&obj_dumper);
+ }
} else {
assert(get_worker_type(worker_id) == DumperType
|| get_worker_type(worker_id) == VMDumperType,
@@ -2418,10 +2930,23 @@ void VM_HeapDumper::work(uint worker_id) {
// Heap iteration.
{
ParDumpWriter pw(writer());
+ pw.setHeapRedactor(writer()->heapRedactor());
{
ResourceMark rm;
- HeapObjectDumper obj_dumper(&pw, _large_object_list);
- _poi->object_iterate(&obj_dumper, worker_id);
+ if(writer()->heapRedactor() != NULL && (writer()->heapRedactor()->redact_level() == REDACT_BASIC ||
+ writer()->heapRedactor()->redact_level() == REDACT_FULL)) {
+ HeapObjectDumper obj_dumper(&pw, DumperSupport::redact_basic_dump_prim_array, _large_object_list);
+ _poi->object_iterate(&obj_dumper, worker_id);
+ } else if(writer()->heapRedactor() != NULL && writer()->heapRedactor()->redact_level() == REDACT_ANNOTATION) {
+ HeapObjectRedactDumper obj_dumper(&pw, DumperSupport::do_lookup_replace_value_with_symbol, _large_object_list, worker_id);
+ _poi->object_iterate(&obj_dumper, worker_id);
+ } else if(writer()->heapRedactor() != NULL && writer()->heapRedactor()->redact_level() == REDACT_DIYRULES) {
+ HeapObjectRedactDumper obj_dumper(&pw, DumperSupport::do_lookup_replace_value_with_char, _large_object_list, worker_id);
+ _poi->object_iterate(&obj_dumper, worker_id);
+ } else {
+ HeapObjectDumper obj_dumper(&pw, DumperSupport::dump_prim_array, _large_object_list);
+ _poi->object_iterate(&obj_dumper, worker_id);
+ }
}
if (get_worker_type(worker_id) == VMDumperType) {
@@ -2441,8 +2966,26 @@ void VM_HeapDumper::work(uint worker_id) {
assert(get_worker_type(worker_id) == VMDumperType, "Heap dumper must be VMDumper");
// Use writer() rather than ParDumpWriter to avoid memory consumption.
ResourceMark rm;
- HeapObjectDumper obj_dumper(writer());
- dump_large_objects(&obj_dumper);
+ if(writer()->heapRedactor() != NULL && (writer()->heapRedactor()->redact_level() == REDACT_BASIC ||
+ writer()->heapRedactor()->redact_level() == REDACT_FULL)) {
+ HeapObjectDumper obj_dumper(writer(), DumperSupport::redact_basic_dump_prim_array);
+ dump_large_objects(&obj_dumper);
+ } else if(writer()->heapRedactor() != NULL && writer()->heapRedactor()->redact_level() == REDACT_ANNOTATION) {
+ HeapObjectRedactDumper obj_dumper(writer(), DumperSupport::do_lookup_replace_value_with_symbol);
+ dump_large_objects(&obj_dumper);
+ } else if(writer()->heapRedactor() != NULL && writer()->heapRedactor()->redact_level() == REDACT_DIYRULES) {
+ HeapObjectRedactDumper obj_dumper(writer(), DumperSupport::do_lookup_replace_value_with_char);
+ dump_large_objects(&obj_dumper);
+ } else {
+ HeapObjectDumper obj_dumper(writer());
+ dump_large_objects(&obj_dumper);
+ }
+
+ // if value in INSTANCE is sensitive
+ // and redact level is REDACT_ANNOTATION
+ // writes HeapVector here
+ do_heapVector();
+
// Writes the HPROF_HEAP_DUMP_END record.
DumperSupport::end_of_dump(writer());
// We are done with writing. Release the worker threads.
@@ -2507,6 +3050,68 @@ void VM_HeapDumper::dump_stack_traces() {
}
}
+void VM_HeapDumper::do_heapVector(){
+ CALL_DO_LOOKUP_REPLACE_VALUE fn = nullptr;
+ if(writer()->getHeapDumpRedactLevel() == REDACT_ANNOTATION) {
+ fn = DumperSupport::do_lookup_replace_value_with_symbol;
+ } else if(writer()->getHeapDumpRedactLevel() == REDACT_DIYRULES) {
+ fn = DumperSupport::do_lookup_replace_value_with_char;
+ } else {
+ return;
+ }
+
+ BasicType type = T_BYTE;
+ short header_size = 2 * 1 + 2 * 4 + sizeof(address);
+ int type_size = type2aelembytes(type);
+ uint max_bytes = max_juint - header_size;
+
+ uint container_nums = writer()->heapRedactor()->get_container_nums();
+ for (uint container_index = 0; container_index < container_nums; container_index++) {
+ int node_len = 0, i =0;
+ void** items = nullptr;
+ void *vector_node = writer()->heapRedactor()->get_vector_node_next(nullptr, node_len, items, container_index);
+ while (vector_node != NULL && items != NULL) {
+ for (i = 0; i < node_len; i++) {
+ typeArrayOop array = (typeArrayOopDesc*)items[i];
+
+ char *anonymous_value = fn(writer(), array);
+ int length = anonymous_value == NULL ? array->length() : strlen(anonymous_value);
+
+ u4 length_in_bytes = (u4) length * type_size;
+ if (length_in_bytes > max_bytes) {
+ length = max_bytes / type_size;
+ length_in_bytes = (size_t)length * type_size;
+ }
+ u4 size = header_size + length_in_bytes;
+
+ writer()->start_sub_record(HPROF_GC_PRIM_ARRAY_DUMP, size);
+ writer()->write_objectID(array);
+ writer()->write_u4(STACK_TRACE_ID);
+ writer()->write_u4(length);
+ writer()->write_u1(HPROF_BYTE);
+
+ // nothing to copy
+ if (length == 0) {
+ writer()->end_sub_record();
+ continue;
+ }
+ if(anonymous_value != nullptr){
+ writer()->write_raw(anonymous_value, length);
+ } else {
+ writer()->write_raw((void *) (array->byte_at_addr(0)), length_in_bytes);
+ }
+ writer()->end_sub_record();
+ }
+
+ // clear current node info, maybe next node items is NULL, node_len = 0 will skip this NULL point error
+ node_len = 0;
+ items = nullptr;
+ void *temp = writer()->heapRedactor()->get_vector_node_next(vector_node, node_len, items, container_index);
+ vector_node = temp;
+ }
+ }
+}
+
// dump the large objects.
void VM_HeapDumper::dump_large_objects(ObjectClosure* cl) {
_large_object_list->drain(cl);
@@ -2516,9 +3121,22 @@ void VM_HeapDumper::dump_large_objects(ObjectClosure* cl) {
int HeapDumper::dump(const char* path, outputStream* out, int compression, bool overwrite, uint num_dump_threads) {
assert(path != nullptr && strlen(path) > 0, "path missing");
+ const char* path_and_anonymous = path;
+ const char* redact_params = nullptr;
+ // parse args[0] to get real path and redact_params
+ const char* split_char = strstr(path_and_anonymous, ";");
+ size_t path_length = (split_char == nullptr) ? strlen(path_and_anonymous) : (unsigned long)(split_char - path_and_anonymous);
+ size_t path_and_anonymous_length = strlen(path_and_anonymous);
+ char* _path = NEW_C_HEAP_ARRAY(char, path_and_anonymous_length + 1, mtInternal);
+ strncpy(_path, path_and_anonymous, path_and_anonymous_length + 1);
+ _path[path_length] = '\0';
+ if (split_char != NULL) {
+ redact_params = split_char + 1;
+ }
+
// print message in interactive case
if (out != nullptr) {
- out->print_cr("Dumping heap to %s ...", path);
+ out->print_cr("Dumping heap to %s ...", _path);
timer()->start();
}
// create JFR event
@@ -2535,17 +3153,26 @@ int HeapDumper::dump(const char* path, outputStream* out, int compression, bool
}
}
- DumpWriter writer(new (std::nothrow) FileWriter(path, overwrite), compressor);
+ HeapRedactor heapRedactor(redact_params, out);
+ DumpWriter writer(new (std::nothrow) FileWriter(_path, overwrite), compressor);
+ if(heapRedactor.redact_level() > REDACT_UNKNOWN) {
+ if(out != NULL) {
+ out->print_cr("HeapDump Redact Level = %s", heapRedactor.get_redact_level_string());
+ }
+ }
+ writer.setHeapRedactor(&heapRedactor);
if (writer.error() != nullptr) {
set_error(writer.error());
if (out != nullptr) {
- out->print_cr("Unable to create %s: %s", path,
- (error() != nullptr) ? error() : "reason unknown");
- }
- return -1;
+ out->print_cr("Unable to create %s: %s", _path,
+ (error() != NULL) ? error() : "reason unknown");
+ }
+ FREE_C_HEAP_ARRAY(char, _path);
+ return -1;
}
+ FREE_C_HEAP_ARRAY(char, _path);
// generate the dump
VM_HeapDumper dumper(&writer, _gc_before_heap_dump, _oome, num_dump_threads);
if (Thread::current()->is_VM_thread()) {
diff --git a/src/hotspot/share/services/heapRedactor.cpp b/src/hotspot/share/services/heapRedactor.cpp
new file mode 100644
index 000000000..9fe4648df
--- /dev/null
+++ b/src/hotspot/share/services/heapRedactor.cpp
@@ -0,0 +1,676 @@
+/*
+ * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Huawei designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Huawei in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please visit https://gitee.com/openeuler/bishengjdk-8 if you need additional
+ * information or have any questions.
+ */
+
+#include "runtime/globals.hpp"
+#include "runtime/os.hpp"
+#include "runtime/arguments.hpp"
+#include "utilities/ostream.hpp"
+#include "memory/allocation.hpp"
+#include "memory/allocation.inline.hpp"
+#include "jvm_md.h"
+#include "utilities/debug.hpp"
+#include "services/heapRedactor.hpp"
+#include "logging/log.hpp"
+#include "logging/logLevel.hpp"
+
+const char* HeapRedactor::REDACT_UNKNOWN_STR = "UNKNOWN";
+const char* HeapRedactor::REDACT_OFF_STR = "OFF";
+const char* HeapRedactor::REDACT_NAMES_STR = "NAMES";
+const char* HeapRedactor::REDACT_BASIC_STR = "BASIC";
+const char* HeapRedactor::REDACT_ANNOTATION_STR = "ANNOTATION";
+const char* HeapRedactor::REDACT_DIYRULES_STR = "DIYRULES";
+const char* HeapRedactor::REDACT_FULL_STR = "FULL";
+
+HeapRedactor::HeapRedactor(outputStream* out) {
+ init_fields();
+ _use_sys_params = true;
+ init(out);
+}
+
+HeapRedactor::HeapRedactor(const char *redact_params_string, outputStream* out) {
+ init_fields();
+ if (redact_params_string != NULL && strlen(redact_params_string) > 0) {
+ _use_sys_params = false;
+ parse_redact_params(redact_params_string);
+ } else {
+ _use_sys_params = true;
+ }
+ init(out);
+}
+
+HeapRedactor::~HeapRedactor() {
+#ifdef LINUX
+ if(_redact_name_table != NULL) {
+ os::Linux::heap_dict_free(_redact_name_table,false);
+ _redact_name_table = NULL;
+ }
+
+ if(_redact_rules_table != NULL) {
+ os::Linux::heap_dict_free(_redact_rules_table, true);
+ _redact_rules_table = NULL;
+ }
+
+ if(_annotation_value_tables != NULL) {
+ for(uint i = 0; i < _container_nums; i++) {
+ if(_annotation_value_tables[i] != NULL) {
+ os::Linux::heap_dict_free(_annotation_value_tables[i], false);
+ _annotation_value_tables[i] = NULL;
+ }
+ }
+ }
+
+ if(_redact_class_field_table != NULL) {
+ os::Linux::heap_dict_free(_redact_class_field_table, true);
+ _redact_class_field_table = NULL;
+ }
+
+ if(_redact_records!= NULL) {
+ for(uint i = 0; i < _container_nums; i++) {
+ if(_redact_records[i] != NULL) {
+ os::Linux::heap_vector_free(_redact_records[i]);
+ _redact_records[i] = NULL;
+ }
+ }
+ }
+#endif
+ if(_annotation_value_tables != NULL) {
+ FREE_C_HEAP_ARRAY(void*, _annotation_value_tables);
+ }
+
+ if(_redact_records != NULL) {
+ FREE_C_HEAP_ARRAY(void*, _redact_records);
+ }
+
+ if(_name_map_list != NULL){
+ FREE_C_HEAP_ARRAY(char, _name_map_list);
+ }
+ if(_file_name_map_list != NULL){
+ FREE_C_HEAP_ARRAY(char, _file_name_map_list);
+ }
+ if(_annotation_class_path != NULL) {
+ FREE_C_HEAP_ARRAY(char, _annotation_class_path);
+ }
+ _file_name_map_list = NULL;
+ _name_map_list = NULL;
+ _annotation_class_path = NULL;
+}
+
+void HeapRedactor::init_fields() {
+ _redact_level = REDACT_UNKNOWN;
+ _redact_name_table = NULL;
+ _redact_rules_table= NULL;
+ _annotation_value_tables = NULL;
+ _redact_records = NULL;
+ _redact_class_field_table = NULL;
+ _file_name_map_list = NULL;
+ _name_map_list = NULL;
+ _redact_class_full_name = NULL;
+ _annotation_class_path = NULL;
+
+ _redact_params.params_string = NULL;
+ _redact_params.heap_dump_redact = NULL;
+ _redact_params.redact_map = NULL;
+ _redact_params.redact_map_file = NULL;
+ _redact_params.annotation_class_path = NULL;
+ _redact_params.redact_password = NULL;
+}
+
+void HeapRedactor::parse_redact_params(const char *redact_params_string) {
+ size_t length = strlen(redact_params_string);
+ char* buf = NEW_C_HEAP_ARRAY(char, length + 1, mtInternal);
+ _redact_params.params_string = buf;
+ strncpy(_redact_params.params_string, redact_params_string, length + 1);
+ size_t start = strlen("-HeapDumpRedact=");
+ _redact_params.heap_dump_redact = _redact_params.params_string + start;
+ char* map_pos = strstr(_redact_params.heap_dump_redact, ",RedactMap=");
+ char* file_pos = strstr(_redact_params.heap_dump_redact, ",RedactMapFile=");
+ char* class_path_pos = strstr(_redact_params.heap_dump_redact, ",RedactClassPath=");
+ char* redact_password_pos = strstr(_redact_params.heap_dump_redact, ",RedactPassword=");
+
+ _redact_params.redact_map = parse_redact_child_param(map_pos, ",RedactMap=",
+ file_pos);
+ _redact_params.redact_map_file = parse_redact_child_param(file_pos, ",RedactMapFile=",
+ class_path_pos);
+ _redact_params.annotation_class_path = parse_redact_child_param(class_path_pos, ",RedactClassPath=",
+ redact_password_pos);
+ _redact_params.redact_password = parse_redact_child_param(redact_password_pos, ",RedactPassword=",
+ _redact_params.params_string + length);
+}
+
+char* HeapRedactor::parse_redact_child_param(char *redact_params_sub_string, const char* redact_param_prefix,
+ const char* next_redact_param_prefix) {
+ char* pos = NULL;
+ if (redact_params_sub_string == NULL) {
+ pos = NULL;
+ } else {
+ *redact_params_sub_string = '\0';
+ pos = redact_params_sub_string + strlen(redact_param_prefix);
+ if (pos == next_redact_param_prefix) {
+ pos = NULL;
+ }
+ }
+ return pos;
+}
+
+bool HeapRedactor::check_launcher_heapdump_redact_support(const char *value) {
+ if (!strcmp(value, "=basic") || !strcmp(value, "=names") || !strcmp(value, "=off")
+ || !strcmp(value, "=diyrules") || !strcmp(value, "=annotation") || !strcmp(value, "=full")) {
+ return true;
+ }
+ return false;
+}
+
+void HeapRedactor::init(outputStream* out) {
+ /** -XX:+VerifyRedactPassword,
+ * if HeapDumpRedact is NULL , jmap operation can not open redact feature without password
+ * if HeapDumpRedact is not NULL, jmap operation can not change redact level without password
+ **/
+ char* split_char = NULL;
+ if(RedactPassword == NULL || (split_char = strstr(const_cast<char*>(RedactPassword), ",")) == NULL || strlen(split_char) < SALT_LEN) {
+ VerifyRedactPassword = false;
+ }
+ if(VerifyRedactPassword && !_use_sys_params) {
+ size_t auth_len = strlen(RedactPassword);
+ size_t suffix_len = strlen(split_char);
+ if(_redact_params.redact_password == NULL ||
+ strncmp(_redact_params.redact_password, RedactPassword, auth_len-suffix_len) ) {
+ // no password or wrong password
+ _use_sys_params = true;
+ if(out != NULL) {
+ out->print_cr("not correct password, use the default redact mode when stared");
+ }
+ }
+ }
+
+ if(_redact_params.redact_password != NULL) {
+ size_t password_Len = strlen(_redact_params.redact_password);
+ memset(_redact_params.redact_password, '\0', password_Len);
+ }
+
+ if (_redact_level == REDACT_UNKNOWN) {
+ init_heapdump_redact_level();
+ }
+ return;
+}
+
+void HeapRedactor::init_redact_map() {
+ const char* map_param = NULL;
+ const char* map_file_param = NULL;
+ if (_use_sys_params) {
+ map_param = RedactMap;
+ map_file_param = RedactMapFile;
+ } else {
+ map_param = _redact_params.redact_map;
+ map_file_param = _redact_params.redact_map_file;
+ }
+ if (map_file_param != NULL) {
+ read_redact_map_from_file(map_file_param);
+ }
+ if (map_param != NULL) {
+ size_t length = strlen(map_param);
+ _name_map_list = NEW_C_HEAP_ARRAY(char, length + 1, mtInternal);
+ strncpy(_name_map_list, map_param, length + 1);
+ read_redact_map_dependon_mode(_name_map_list, _redact_level);
+ }
+}
+
+void HeapRedactor::read_redact_map_dependon_mode(char* name_map_list, HeapDumpRedactLevel redact_level) {
+ if(redact_level == REDACT_DIYRULES) {
+ parse_redact_diy_rules(name_map_list);
+ } else {
+ parse_redact_map_string(name_map_list);
+ }
+}
+
+void HeapRedactor::parse_redact_map_string(char *name_map_list) {
+#ifdef LINUX
+ size_t token_start = 0;
+ size_t step = 0;
+ size_t length = strlen(name_map_list);
+
+ while (step < length) {
+ bool is_seperator = false;
+ if ((is_seperator = (name_map_list[step] == ',' || name_map_list[step] == ';' || name_map_list[step] == '\n' ||
+ name_map_list[step] == ' ')) ||
+ step == length - 1) {
+ if (is_seperator) {
+ name_map_list[step] = '\0';
+ } else {
+ step++;
+ }
+
+ if (token_start >= step) {
+ // to reduce the depth of the method
+ token_start = step + 1;
+ continue;
+ }
+
+ char *token = name_map_list + token_start;
+ size_t i = 0;
+ size_t token_length = strlen(token);
+ while (i < token_length && token[i] != ':') {
+ i++;
+ }
+ if (i < token_length - 1) {
+ token[i] = '\0';
+ _redact_name_table = os::Linux::heap_dict_add(token, token + i + 1, _redact_name_table, 0);
+ }
+ token_start = step + 1;
+ }
+ step++;
+ }
+#endif
+}
+
+void HeapRedactor::read_redact_map_from_file(const char *path) {
+ char base_path[JVM_MAXPATHLEN] = {'\0'};
+ char buffer[MAX_MAP_FILE_LENGTH + 1] = {'\0'};
+ if (path == NULL || path[0] == '\0') {
+ // RedactMapFile=<file> not specified
+ } else {
+ if (strlen(path) >= JVM_MAXPATHLEN) {
+ warning("RedactMap File path is too long ");
+ return;
+ }
+ strncpy(base_path, path, sizeof(base_path));
+ // check if the path is a directory (must exist)
+ FILE* fm = NULL;
+ fm = fopen(base_path, "r");
+ if (fm == NULL) {
+ return;
+ }
+ size_t num_read = fread((char *)buffer, 1, MAX_MAP_FILE_LENGTH, fm);
+ if((int)num_read != -1){
+ _file_name_map_list = NEW_C_HEAP_ARRAY(char, (size_t)num_read + 1, mtInternal);
+ strncpy(_file_name_map_list, buffer, num_read + 1);
+ read_redact_map_dependon_mode(_file_name_map_list, _redact_level);
+ }
+
+ fclose(fm);
+ }
+}
+
+void HeapRedactor::parse_redact_diy_rules(char* name_map_list) {
+ size_t token_start = 0;
+ size_t step = 0;
+ size_t length = strlen(name_map_list);
+
+ while (step < length) {
+ bool is_seperator = false;
+ if ((is_seperator = (name_map_list[step] == ',' || name_map_list[step] == ';' || name_map_list[step] == '\n' ||
+ name_map_list[step] == ' ')) ||
+ step == length - 1) {
+ if (is_seperator) {
+ name_map_list[step] = '\0';
+ } else {
+ step++;
+ }
+
+ if (token_start >= step) {
+ // to reduce the depth of the method
+ token_start = step + 1;
+ continue;
+ }
+
+ char *token = name_map_list + token_start;
+ parse_token(token);
+ token_start = step + 1;
+ }
+ step++;
+ }
+
+ // clear _redact_class_full_name, encase RedactMap has an unformatted value(without class name),
+ // will rewrite the last class's value_map
+ _redact_class_full_name = NULL;
+}
+
+void HeapRedactor::parse_token(char* token) {
+#ifdef LINUX
+ size_t i = 0;
+ size_t token_length = strlen(token);
+ while (i < token_length && token[i] != ':') {
+ if(token[i] == '.' ) {
+ token[i] = '/';
+ }
+ i++;
+ }
+
+ void* _redact_rules_sub_table = _redact_class_full_name == NULL ? NULL :
+ os::Linux::heap_dict_lookup(_redact_class_full_name, _redact_rules_table, false);
+ if (i < token_length - 1 && _redact_rules_sub_table != NULL) {
+ token[i] = '\0';
+ os::Linux::heap_dict_add(token, token + i + 1, _redact_rules_sub_table, 0);
+ } else if( i == token_length) {
+ _redact_class_full_name = token;
+ _redact_rules_sub_table = os::Linux::heap_dict_lookup(token, _redact_rules_table, false);
+ if (_redact_rules_sub_table == NULL) {
+ _redact_rules_sub_table = os::Linux::heap_dict_add(token, NULL, _redact_rules_sub_table, 0);
+ _redact_rules_table = os::Linux::heap_dict_add(token, _redact_rules_sub_table, _redact_rules_table, 0);
+ }
+ }
+#endif
+}
+
+HeapDumpRedactLevel HeapRedactor::init_heapdump_redact_level() {
+ const char* redact_string = NULL;
+ if (_use_sys_params) {
+ redact_string = HeapDumpRedact;
+ } else {
+ redact_string = _redact_params.heap_dump_redact;
+ }
+ if (redact_string == NULL) {
+ _redact_level = REDACT_OFF;
+ } else {
+#ifdef LINUX
+ if (strcmp(redact_string, "basic") == 0) {
+ _redact_level = REDACT_BASIC;
+ } else if (strcmp(redact_string, "names") == 0) {
+ _redact_level = REDACT_NAMES;
+ init_redact_map();
+ } else if (strcmp(redact_string, "full") == 0) {
+ _redact_level = REDACT_FULL;
+ init_redact_map();
+ } else if (strcmp(redact_string, "diyrules") == 0) {
+ _redact_level = REDACT_DIYRULES;
+ init_redact_map();
+ } else if (strcmp(redact_string, "annotation") == 0) {
+ _redact_level = REDACT_ANNOTATION;
+ init_class_path();
+ if(_annotation_class_path == NULL) {
+ _redact_level = REDACT_OFF;
+ }
+ } else {
+ _redact_level = REDACT_OFF;
+ }
+#else
+ if (strcmp(redact_string, "basic") == 0) {
+ _redact_level = REDACT_BASIC;
+ } else if (strcmp(redact_string, "full") == 0) {
+ _redact_level = REDACT_BASIC;
+ } else {
+ _redact_level = REDACT_OFF;
+ }
+#endif
+
+ }
+
+ if (_redact_params.params_string != NULL) {
+ FREE_C_HEAP_ARRAY(char, _redact_params.params_string);
+ }
+ return _redact_level;
+}
+
+void HeapRedactor::init_class_path() {
+ const char* class_path = NULL;
+ if (_use_sys_params) {
+ class_path = RedactClassPath;
+ } else {
+ class_path = _redact_params.annotation_class_path;
+ }
+
+ if(class_path != NULL) {
+ size_t class_path_len = strlen(class_path);
+ _annotation_class_path = NEW_C_HEAP_ARRAY(char, class_path_len + 3, mtInternal);
+ _annotation_class_path[0] = 'L';
+ strncpy(_annotation_class_path + 1, class_path, class_path_len + 1);
+ _annotation_class_path[class_path_len + 1] = ';';
+ _annotation_class_path[class_path_len + 2] = '\0';
+ }
+}
+
+void HeapRedactor::insert_anonymous_value(void* key, void* value, uint index){
+#ifdef LINUX
+ _annotation_value_tables[index] = os::Linux::heap_dict_add(key, value, _annotation_value_tables[index], 1);
+#endif
+}
+
+bool HeapRedactor::recursion_cp_refs_in_annotation_struct(
+ AnnotationArray* annotations_typeArray, int &byte_i_ref) {
+ if ((byte_i_ref + 2 + 2) > annotations_typeArray->length()) {
+ // not enough room for smallest annotation_struct
+ if (log_is_enabled(Debug, cds, heap)) {
+ log_debug(cds, heap)("length() is too small for annotation_struct");
+ }
+ return false;
+ }
+
+ u2 type_index = Bytes::get_Java_u2((address)annotations_typeArray->adr_at(byte_i_ref));
+ byte_i_ref += 2;
+
+ u2 num_element_value_pairs = Bytes::get_Java_u2((address) annotations_typeArray->adr_at(byte_i_ref));
+ byte_i_ref += 2;
+
+ if (log_is_enabled(Debug, cds, heap)) {
+ log_debug(cds, heap)("type_index=%d num_element_value_pairs=%d", type_index, num_element_value_pairs);
+ }
+
+ int calc_num_element_value_pairs = 0;
+ for (; calc_num_element_value_pairs < num_element_value_pairs;
+ calc_num_element_value_pairs++) {
+ if ((byte_i_ref + 2) > annotations_typeArray->length()) {
+ // not enough room for another element_name_index, let alone
+ // the rest of another component
+ log_debug(cds, heap)("length() is too small for element_name_index");
+ return false;
+ }
+
+ u2 element_name_index = Bytes::get_Java_u2((address) annotations_typeArray->adr_at(byte_i_ref));
+ byte_i_ref += 2;
+
+ log_debug(cds, heap)("element_name_index=%d", element_name_index);
+
+ if (!recursion_cp_refs_in_element_value(annotations_typeArray, byte_i_ref)) {
+ log_debug(cds, heap)("bad element_value at %d", calc_num_element_value_pairs);
+ // propagate failure back to caller
+ return false;
+ }
+ } // end for each component
+ assert(num_element_value_pairs == calc_num_element_value_pairs, "sanity check");
+
+ return true;
+} // end recursion_cp_refs_in_annotation_struct()
+
+bool HeapRedactor::lookup_annotation_index_in_constant_pool(AnnotationArray* field_annotations, ConstantPool *cp, int &byte_i_ref) {
+ u2 num_annotations = 0;
+ bool has_anonymous_annotation = false;
+
+ if ((byte_i_ref + 2) > field_annotations->length()) {
+ // not enough room for num_annotations field
+ log_debug(cds, heap)("length() is too small for num_annotations field");
+ return false;
+ } else {
+ num_annotations = Bytes::get_Java_u2((address) field_annotations->adr_at(byte_i_ref));
+ }
+
+ byte_i_ref += 2;
+
+ for (int calc_num_annotations = 0; calc_num_annotations < num_annotations; calc_num_annotations++) {
+
+ if ((byte_i_ref + 2 + 2) > field_annotations->length()) {
+ // not enough room for smallest annotation_struct
+ log_debug(cds, heap)("length() is too small for annotation_struct");
+ return false;
+ }
+
+ // get constants pool index
+ address cp_index_addr = (address) field_annotations->adr_at(byte_i_ref);
+ byte_i_ref += 2;
+ u2 cp_index = Bytes::get_Java_u2(cp_index_addr);
+ Symbol *annotate_class_symbol = cp->symbol_at(cp_index);
+ if (!Symbol::is_valid(annotate_class_symbol)) {
+ return false;
+ }
+ char *annotate_class_name = annotate_class_symbol->as_C_string();
+
+ u2 num_element_value_pairs = Bytes::get_Java_u2((address) field_annotations->adr_at(byte_i_ref));
+ byte_i_ref += 2;
+ if ((byte_i_ref + 2 + 1) > field_annotations->length()) {
+ // not enough room for smallest annotation_struct
+ log_debug(cds, heap)("length() is too small for element_name_index");
+ return false;
+ }
+
+ const char *annotation_class_path = get_annotation_class_path();
+ has_anonymous_annotation = (strcmp(annotation_class_path, annotate_class_name) == 0);
+ if (has_anonymous_annotation) {
+ address element_name_addr = (address) field_annotations->adr_at(byte_i_ref);
+ byte_i_ref += 2;
+ u2 cp_name_index = Bytes::get_Java_u2(element_name_addr);
+ Symbol *element_name_symbol = cp->symbol_at(cp_name_index);
+ char *element_name = element_name_symbol->as_C_string();
+ if(element_name == NULL || strcmp(element_name, "value")) {
+ // expected annotation has only one field "value"
+ return false;
+ }
+ // skip element tag
+ byte_i_ref++;
+ return true;
+ }
+
+ int calc_num_element_value_pairs = 0;
+ // skip element_name_index
+ byte_i_ref += 2;
+ for (; calc_num_element_value_pairs < num_element_value_pairs; calc_num_element_value_pairs++) {
+ if (!recursion_cp_refs_in_element_value(field_annotations, byte_i_ref)) {
+ return false;
+ }
+ }
+ }
+ return false;
+}
+
+bool HeapRedactor::recursion_cp_refs_in_element_value(AnnotationArray* field_annotations, int &byte_i_ref) {
+ if ((byte_i_ref + 1) > field_annotations->length()) {
+ // not enough room for a tag let alone the rest of an element_value
+ if (log_is_enabled(Debug, cds, heap)) {
+ log_debug(cds, heap)("length() is too small for a tag");
+ }
+ return false;
+ }
+
+ u1 tag = field_annotations->at(byte_i_ref);
+ byte_i_ref++;
+ switch (tag) {
+ case JVM_SIGNATURE_BYTE:
+ case JVM_SIGNATURE_CHAR:
+ case JVM_SIGNATURE_DOUBLE:
+ case JVM_SIGNATURE_FLOAT:
+ case JVM_SIGNATURE_INT:
+ case JVM_SIGNATURE_LONG:
+ case JVM_SIGNATURE_SHORT:
+ case JVM_SIGNATURE_BOOLEAN:
+ case 's':
+ case 'c':
+ {
+ if ((byte_i_ref + 2) > field_annotations->length()) {
+ if (log_is_enabled(Debug, cds, heap)) {
+ log_debug(cds, heap)("length() is too small for a const_value_index");
+ }
+ break;
+ }
+ byte_i_ref += 2;
+ } break;
+ case 'e':
+ {
+ if ((byte_i_ref + 4) > field_annotations->length()) {
+ if (log_is_enabled(Debug, cds, heap)) {
+ log_debug(cds, heap)("length() is too small for a enum_const_value");
+ }
+ break;
+ }
+ byte_i_ref += 4;
+ } break;
+
+ case '@':
+ // For the above tag value, value.attr_value is the right union
+ // field. This is a nested annotation.
+ if (!recursion_cp_refs_in_annotation_struct(field_annotations, byte_i_ref)) {
+ // propagate failure back to caller
+ return false;
+ }
+ break;
+
+ case JVM_SIGNATURE_ARRAY:
+ {
+ if ((byte_i_ref + 2) > field_annotations->length()) {
+ // not enough room for a num_values field
+ if (log_is_enabled(Debug, cds, heap)) {
+ log_debug(cds, heap)("length() is too small for a num_values field");
+ }
+ return false;
+ }
+
+ // For the above tag value, value.array_value is the right union
+ // field. This is an array of nested element_value.
+ u2 num_values = Bytes::get_Java_u2((address) field_annotations->adr_at(byte_i_ref));
+ byte_i_ref += 2;
+ if (log_is_enabled(Debug, cds, heap)) {
+ log_debug(cds, heap)("num_values=%d", num_values);
+ }
+
+ int calc_num_values = 0;
+ for (; calc_num_values < num_values; calc_num_values++) {
+ if (!recursion_cp_refs_in_element_value(field_annotations, byte_i_ref)) {
+ if (log_is_enabled(Debug, cds, heap)) {
+ log_debug(cds, heap)("bad nested element_value at %d", calc_num_values);
+ }
+ // propagate failure back to caller
+ return false;
+ }
+ }
+ } break;
+
+ default:
+ if (log_is_enabled(Debug, cds, heap)) {
+ log_debug(cds, heap)("bad tag=0x%x", tag);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool HeapRedactor::record_typeArrayOop(typeArrayOop array, uint index) {
+ bool _inserted = false;
+#ifdef LINUX
+ _redact_records[index] = os::Linux::heap_vector_add(array, _redact_records[index], _inserted);
+#endif
+ return _inserted;
+}
+
+void HeapRedactor::insert_class_field_value(void* class_key, void* field_key, void* value) {
+#ifdef LINUX
+ void* _redact_sub_table = os::Linux::heap_dict_lookup(class_key, _redact_class_field_table, false);
+ _redact_sub_table = os::Linux::heap_dict_add(field_key, value, _redact_sub_table, 1);
+ _redact_class_field_table = os::Linux::heap_dict_add(class_key, _redact_sub_table, _redact_class_field_table, 1);
+#endif
+}
+
+void HeapRedactor::init_containers(uint nums) {
+ _container_nums = (nums == 0 ? 1 : nums);
+ _annotation_value_tables = NEW_C_HEAP_ARRAY(void*, _container_nums, mtInternal);
+ memset(_annotation_value_tables, 0, sizeof(void*)*_container_nums);
+ _redact_records = NEW_C_HEAP_ARRAY(void*, _container_nums, mtInternal);
+ memset(_redact_records, 0, sizeof(void*)*_container_nums);
+}
\ No newline at end of file
diff --git a/src/hotspot/share/services/heapRedactor.hpp b/src/hotspot/share/services/heapRedactor.hpp
new file mode 100644
index 000000000..467baa39d
--- /dev/null
+++ b/src/hotspot/share/services/heapRedactor.hpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Huawei designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Huawei in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please visit https://gitee.com/openeuler/bishengjdk-8 if you need additional
+ * information or have any questions.
+ */
+
+#ifndef SHARE_SERVICES_HEAPREDACTOR_HPP
+#define SHARE_SERVICES_HEAPREDACTOR_HPP
+#include "memory/allocation.hpp"
+#include "oops/annotations.hpp"
+#include "oops/constantPool.hpp"
+#ifdef LINUX
+#include "os_linux.hpp"
+#endif
+
+#define MAX_MAP_FILE_LENGTH 1024
+#define SALT_LEN 9
+
+enum HeapDumpRedactLevel {
+ REDACT_UNKNOWN,
+ REDACT_OFF,
+ REDACT_NAMES,
+ REDACT_BASIC,
+ REDACT_DIYRULES,
+ REDACT_ANNOTATION,
+ REDACT_FULL
+};
+
+struct RedactParams {
+ char* params_string;
+ char* heap_dump_redact;
+ char* redact_map;
+ char* redact_map_file;
+ char* annotation_class_path;
+ char* redact_password;
+};
+
+class HeapRedactor : public StackObj {
+public:
+ static const char* REDACT_UNKNOWN_STR;
+ static const char* REDACT_OFF_STR;
+ static const char* REDACT_NAMES_STR;
+ static const char* REDACT_BASIC_STR;
+ static const char* REDACT_DIYRULES_STR;
+ static const char* REDACT_ANNOTATION_STR;
+ static const char* REDACT_FULL_STR;
+ HeapRedactor(outputStream* out);
+ HeapRedactor(const char* redact_params, outputStream* out);
+ ~HeapRedactor();
+ static bool check_launcher_heapdump_redact_support(const char* value);
+ HeapDumpRedactLevel redact_level() {
+ if(_redact_level == REDACT_UNKNOWN) {
+ _redact_level = init_heapdump_redact_level();
+ }
+
+ return _redact_level;
+ }
+
+ const char* get_redact_level_string() const {
+#ifdef LINUX
+ switch (_redact_level) {
+ case REDACT_OFF:
+ return REDACT_OFF_STR;
+ case REDACT_NAMES:
+ return REDACT_NAMES_STR;
+ case REDACT_BASIC:
+ return REDACT_BASIC_STR;
+ case REDACT_DIYRULES:
+ return REDACT_DIYRULES_STR;
+ case REDACT_ANNOTATION:
+ return REDACT_ANNOTATION_STR;
+ case REDACT_FULL:
+ return REDACT_FULL_STR;
+ case REDACT_UNKNOWN:
+ default:
+ return REDACT_UNKNOWN_STR;
+ }
+#else
+ switch (_redact_level) {
+ case REDACT_OFF:
+ return REDACT_OFF_STR;
+ case REDACT_BASIC:
+ return REDACT_BASIC_STR;
+ case REDACT_UNKNOWN:
+ default:
+ return REDACT_UNKNOWN_STR;
+ }
+#endif
+
+ }
+
+ char* lookup_redact_name(const void* name) {
+ void* val = NULL;
+#ifdef LINUX
+ val = os::Linux::heap_dict_lookup(const_cast<void*>(name), _redact_name_table, false);
+#endif
+ if(val != NULL) {
+ return (char*)val;
+ }
+ return NULL;
+ }
+
+ void* lookup_class_rules(const void* name) {
+ void* val = NULL;
+#ifdef LINUX
+ val = os::Linux::heap_dict_lookup(const_cast<void*>(name), _redact_rules_table, false);
+#endif
+ return val;
+ }
+
+ const char* get_annotation_class_path(){
+ return _annotation_class_path;
+ }
+
+ void insert_anonymous_value(void* key, void* value, uint index);
+
+ template<typename T>
+ T lookup_replace_value(void* key) {
+ void* val = NULL;
+#ifdef LINUX
+ for(uint i = 0; i < _container_nums; i++) {
+ if(_annotation_value_tables[i] == NULL) {
+ continue;
+ }
+ val = os::Linux::heap_dict_lookup(key, _annotation_value_tables[i], true);
+ if(val != NULL) {
+ break;
+ }
+ }
+#endif
+ if(val != NULL) {
+ return (T)val;
+ }
+ return NULL;
+ }
+
+ bool lookup_annotation_index_in_constant_pool(AnnotationArray* field_annotations, ConstantPool *cp, int &byte_i_ref);
+ bool recursion_cp_refs_in_element_value(AnnotationArray* field_annotations, int &byte_i_ref);
+ bool recursion_cp_refs_in_annotation_struct(AnnotationArray* field_annotations, int &byte_i_ref);
+
+ bool record_typeArrayOop(typeArrayOop array, uint index);
+ void* get_vector_node_next(void* node, int &_cnt, void** &_items, uint index) {
+ void* val = NULL;
+#ifdef LINUX
+ val = os::Linux::heap_vector_get_next(_redact_records[index], node, _cnt, _items);
+#endif
+ return val;
+ }
+
+ void insert_class_field_value(void* class_key, void* field_key, void* value);
+ void* lookup_class_value(void* key) {
+ void* val = NULL;
+#ifdef LINUX
+ if(_redact_class_field_table == NULL) {
+ return val;
+ }
+ val = os::Linux::heap_dict_lookup(key, _redact_class_field_table, false);
+#endif
+ return val;
+ }
+
+ void* lookup_value(void* key, void* heap_dict, bool deletable) {
+ void* val = NULL;
+#ifdef LINUX
+ val = os::Linux::heap_dict_lookup(key, heap_dict, deletable);
+#endif
+ return val;
+ }
+
+ void init_containers(uint nums);
+ const uint get_container_nums() {
+ return _container_nums;
+ }
+
+private:
+ HeapDumpRedactLevel _redact_level;
+ RedactParams _redact_params;
+ bool _use_sys_params;
+ void* _redact_name_table;
+ void* _redact_rules_table;
+ void** _annotation_value_tables;
+ // void* _annotation_value_table;
+ void* _redact_class_field_table;
+ char* _file_name_map_list;
+ char* _name_map_list;
+ char* _annotation_class_path;
+ char* _redact_class_full_name;
+ void** _redact_records;
+ //void* _redact_record;
+ // safety: every dump thread has one map and one vector
+ uint _container_nums;
+
+ HeapDumpRedactLevel init_heapdump_redact_level();
+ void read_redact_map_from_file(const char* path);
+ void read_redact_map_dependon_mode(char* name_map_list, HeapDumpRedactLevel redact_level);
+ void parse_redact_map_string(char* name_map_list);
+ void parse_redact_diy_rules(char* name_map_list);
+ void parse_token(char* token);
+ void parse_redact_params(const char *redact_params_string);
+ char* parse_redact_child_param(char *redact_params_sub_string, const char* redact_param_prefix, const char* next_redact_param_prefix);
+ void init(outputStream* out);
+ void init_fields();
+ void init_redact_map();
+ void init_class_path();
+
+};
+#endif // SHARE_SERVICES_HEAPREDACTOR_HPP
\ No newline at end of file
diff --git a/src/hotspot/share/services/writeableFlags.cpp b/src/hotspot/share/services/writeableFlags.cpp
index d4f601ed8..6e8924c86 100644
--- a/src/hotspot/share/services/writeableFlags.cpp
+++ b/src/hotspot/share/services/writeableFlags.cpp
@@ -235,6 +235,13 @@ JVMFlag::Error WriteableFlags::set_flag(const char* name, const void* value, JVM
JVMFlag* f = JVMFlag::find_flag(name);
if (f) {
+ if(VerifyRedactPassword) {
+ if(strcmp(name, "HeapDumpRedact") == 0 || strcmp(name, "RedactMap") == 0 || strcmp(name, "RedactMapFile") == 0
+ || strcmp(name, "RedactClassPath") == 0) {
+ err_msg.print("has no authority to reset redact params");
+ return JVMFlag::NON_WRITABLE;
+ }
+ }
// only writeable flags are allowed to be set
if (f->is_writeable()) {
return setter(f, value, origin, err_msg);
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java
index 9cc51934d..80d64ea97 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java
@@ -41,15 +41,16 @@ import sun.jvm.hotspot.gc.g1.*;
import sun.jvm.hotspot.gc.x.*;
import sun.jvm.hotspot.gc.z.*;
import sun.jvm.hotspot.interpreter.*;
-import sun.jvm.hotspot.oops.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.ui.*;
+import sun.jvm.hotspot.ui.Annotation;
import sun.jvm.hotspot.ui.tree.*;
import sun.jvm.hotspot.ui.classbrowser.*;
import sun.jvm.hotspot.utilities.*;
import sun.jvm.hotspot.utilities.Observable;
import sun.jvm.hotspot.utilities.Observer;
-
+import sun.jvm.hotspot.oops.*;
+
/** The top-level HotSpot Debugger. FIXME: make this an embeddable
component! (Among other things, figure out what to do with the
menu bar...) */
@@ -1003,7 +1004,7 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
}
if (curFrame.getFP() != null) {
- annoPanel.addAnnotation(new Annotation(curFrame.getSP(),
+ annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(curFrame.getSP(),
curFrame.getFP(),
anno));
} else {
@@ -1013,14 +1014,14 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
if (Assert.ASSERTS_ENABLED) {
Assert.that(cb.getFrameSize() > 0, "CodeBlob must have non-zero frame size");
}
- annoPanel.addAnnotation(new Annotation(sp,
+ annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(sp,
sp.addOffsetTo(cb.getFrameSize()),
anno));
}
// Add interpreter frame annotations
if (curFrame.isInterpretedFrame()) {
- annoPanel.addAnnotation(new Annotation(curFrame.addressOfInterpreterFrameExpressionStack(),
+ annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(curFrame.addressOfInterpreterFrameExpressionStack(),
curFrame.addressOfInterpreterFrameTOS(),
"Interpreter expression stack"));
Address monBegin = curFrame.interpreterFrameMonitorBegin().address();
@@ -1032,7 +1033,7 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
if (interpreterFrameMethod != null) {
// The offset is just to get the right stack slots highlighted in the output
int offset = 1;
- annoPanel.addAnnotation(new Annotation(curFrame.addressOfInterpreterFrameLocal(offset),
+ annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(curFrame.addressOfInterpreterFrameLocal(offset),
curFrame.addressOfInterpreterFrameLocal((int) interpreterFrameMethod.getMaxLocals() + offset),
"Interpreter locals area for frame with SP = " + curFrame.getSP()));
}
@@ -1041,9 +1042,9 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
methodAnno += " (BAD OOP)";
}
Address a = curFrame.addressOfInterpreterFrameMethod();
- annoPanel.addAnnotation(new Annotation(a, a.addOffsetTo(addressSize), methodAnno));
+ annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(a, a.addOffsetTo(addressSize), methodAnno));
a = curFrame.addressOfInterpreterFrameCPCache();
- annoPanel.addAnnotation(new Annotation(a, a.addOffsetTo(addressSize), "Interpreter constant pool cache"));
+ annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(a, a.addOffsetTo(addressSize), "Interpreter constant pool cache"));
}
RegisterMap rm = (RegisterMap) vf.getRegisterMap().clone();
@@ -1160,7 +1161,7 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
}
}
- annoPanel.addAnnotation(new Annotation(addr, addr.addOffsetTo(addressSize), anno));
+ annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(addr, addr.addOffsetTo(addressSize), anno));
}
}, rm);
} catch (Exception e) {
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java
index b884058a3..1adabf833 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java
@@ -130,6 +130,10 @@ public class SALauncher {
System.out.println(" --histo To print histogram of java object heap.");
System.out.println(" --clstats To print class loader statistics.");
System.out.println(" --finalizerinfo To print information on objects awaiting finalization.");
+ System.out.println(" --HeapDumpRedact <basic|names|full|annotation|diyrules|off> redact the heapdump information to remove sensitive data.");
+ System.out.println(" --RedactMap <name1:value1;name2:value2;...> Redact the class and field names to other strings.");
+ System.out.println(" --RedactMapFile <file> file path of the redact map.");
+ System.err.println(" --RedactClassPath <classpath> full path of the redact annotation");
return commonHelpWithConnect("jmap");
}
@@ -302,8 +306,8 @@ public class SALauncher {
jstack.runWithArgs(buildAttachArgs(newArgMap, false));
}
- private static void runJMAP(String[] oldArgs) {
- Map<String, String> longOptsMap = Map.ofEntries(
+ private static Map<String, String> getLongOptsMap() {
+ return Map.ofEntries(
Map.entry("exe=", "exe"),
Map.entry("core=", "core"),
Map.entry("pid=", "pid"),
@@ -314,13 +318,27 @@ public class SALauncher {
Map.entry("gz=", "gz"),
Map.entry("histo", "-histo"),
Map.entry("clstats", "-clstats"),
- Map.entry("finalizerinfo", "-finalizerinfo"));
+ Map.entry("finalizerinfo", "-finalizerinfo"),
+ Map.entry("HeapDumpRedact=", "HeapDumpRedact"),
+ Map.entry("RedactMap=", "RedactMap"),
+ Map.entry("RedactMapFile=", "RedactMapFile"),
+ Map.entry("RedactClassPath=", "RedactClassPath"),
+ Map.entry("RedactPassword", "RedactPassword"));
+ }
+
+ private static void runJMAP(String[] oldArgs) {
+ Map<String, String> longOptsMap = getLongOptsMap();
Map<String, String> newArgMap = parseOptions(oldArgs, longOptsMap);
boolean requestHeapdump = newArgMap.containsKey("binaryheap");
String dumpfile = newArgMap.get("dumpfile");
String gzLevel = newArgMap.get("gz");
String command = "-heap:format=b";
+ String heapDumpRedact = newArgMap.get("HeapDumpRedact");
+ String redactMap = newArgMap.get("RedactMap");
+ String redactMapFile = newArgMap.get("RedactMapFile");
+ String redactClassPath = newArgMap.get("RedactClassPath");
+ boolean hasRedactPassword = newArgMap.containsKey("RedactPassword");
if (!requestHeapdump && (dumpfile != null)) {
throw new IllegalArgumentException("Unexpected argument: dumpfile");
}
@@ -331,15 +349,37 @@ public class SALauncher {
if (dumpfile != null) {
command += ",file=" + dumpfile;
}
+ if (heapDumpRedact != null) {
+ command += ",HeapDumpRedact=" + heapDumpRedact;
+ }
+ if (redactMap != null) {
+ command += ",RedactMap=" + redactMap;
+ }
+ if (redactMapFile != null) {
+ command += ",RedactMapFile=" + redactMapFile;
+ }
+ if (redactClassPath != null) {
+ command += ",RedactClassPath=" + redactClassPath;
+ }
+ if(hasRedactPassword) {
+ command += ",RedactPassword";
+ }
newArgMap.put(command, null);
}
newArgMap.remove("binaryheap");
newArgMap.remove("dumpfile");
newArgMap.remove("gz");
+ newArgMap.remove("HeapDumpRedact");
+ newArgMap.remove("RedactMap");
+ newArgMap.remove("RedactMapFile");
+ newArgMap.remove("RedactClassPath");
+ newArgMap.remove("RedactPassword");
JMap.main(buildAttachArgs(newArgMap, false));
}
+
+
private static void runJINFO(String[] oldArgs) {
Map<String, String> longOptsMap = Map.of("exe=", "exe",
"core=", "core",
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Annotation.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Annotation.java
new file mode 100644
index 000000000..617e8952b
--- /dev/null
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Annotation.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.oops;
+
+import sun.jvm.hotspot.debugger.Address;
+import sun.jvm.hotspot.runtime.VM;
+import sun.jvm.hotspot.runtime.VMObject;
+import sun.jvm.hotspot.types.AddressField;
+import sun.jvm.hotspot.types.Type;
+import sun.jvm.hotspot.types.TypeDataBase;
+import sun.jvm.hotspot.types.WrongTypeException;
+import sun.jvm.hotspot.utilities.AnnotationArray2D;
+import sun.jvm.hotspot.utilities.Observable;
+import sun.jvm.hotspot.utilities.Observer;
+
+// An Annotation is an oop containing class annotations
+
+public class Annotation extends VMObject {
+ private static AddressField class_annotations;
+ private static AddressField class_type_annotations;
+ private static AddressField fields_annotations;
+ private static AddressField fields_type_annotations;
+
+ static {
+ VM.registerVMInitializedObserver(new Observer() {
+ public void update(Observable o, Object data) {
+ initialize(VM.getVM().getTypeDataBase());
+ }
+ });
+ }
+
+ private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
+ Type type = db.lookupType("Annotations");
+ class_annotations = type.getAddressField("_class_annotations");
+ class_type_annotations = type.getAddressField("_class_type_annotations");
+ fields_annotations = type.getAddressField("_fields_annotations");
+ fields_type_annotations = type.getAddressField("_fields_type_annotations");
+ }
+
+ public Annotation(Address addr) {
+ super(addr);
+ }
+
+ public AnnotationArray2D getFieldsAnnotations() {
+ Address addr = getAddress().getAddressAt(fields_annotations.getOffset());
+ return new AnnotationArray2D(addr);
+ }
+}
\ No newline at end of file
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java
index ebf571c7b..98cb416c9 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java
@@ -131,6 +131,8 @@ public class Field {
private Symbol genericSignature;
private AccessFlags accessFlags;
private int fieldIndex;
+ // java field redact annotation
+ private U1Array fieldAnnotations;
/** Returns the byte offset of the field within the object or klass */
public long getOffset() { return offset; }
@@ -182,6 +184,14 @@ public class Field {
public boolean hasInitialValue() { return holder.getFieldInitialValueIndex(fieldIndex) != 0; }
public int getInitialValueIndex() { return values.initialValueIndex; }
+ public void setFieldAnnotations(U1Array fieldAnnotations){
+ this.fieldAnnotations = fieldAnnotations;
+ }
+
+ public U1Array getFieldAnnotations(){
+ return fieldAnnotations;
+ }
+
//
// Following accessors are for named, non-VM fields only
//
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
index cec603be2..719aa8435 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
@@ -75,6 +75,7 @@ public class InstanceKlass extends Klass {
constants = new MetadataField(type.getAddressField("_constants"), 0);
sourceDebugExtension = type.getAddressField("_source_debug_extension");
innerClasses = type.getAddressField("_inner_classes");
+ annotate = type.getAddressField("_annotations");
nonstaticFieldSize = new CIntField(type.getCIntegerField("_nonstatic_field_size"), 0);
staticFieldSize = new CIntField(type.getCIntegerField("_static_field_size"), 0);
staticOopFieldCount = new CIntField(type.getCIntegerField("_static_oop_field_count"), 0);
@@ -145,6 +146,7 @@ public class InstanceKlass extends Klass {
private static CIntField initState;
private static CIntField itableLen;
private static AddressField breakpoints;
+ private static AddressField annotate;
// type safe enum for ClassState from instanceKlass.hpp
public static class ClassState {
@@ -854,6 +856,10 @@ public class InstanceKlass extends Klass {
return VMObjectFactory.newObject(U2Array.class, addr);
}
+ public Annotation getAnnotation() {
+ Address addr = getAddress().getAddressAt(annotate.getOffset());
+ return VMObjectFactory.newObject(Annotation.class, addr);
+ }
//----------------------------------------------------------------------
// Internals only below this point
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JMap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JMap.java
index 4c80ecd6c..fbead3ce4 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JMap.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JMap.java
@@ -25,6 +25,9 @@
package sun.jvm.hotspot.tools;
import java.io.*;
+import java.nio.CharBuffer;
+import java.util.regex.Pattern;
+
import sun.jvm.hotspot.debugger.JVMDebugger;
import sun.jvm.hotspot.utilities.*;
@@ -78,6 +81,7 @@ public class JMap extends Tool {
private static String dumpfile = "heap.bin";
private static int gzLevel = 0;
+ private static HeapRedactor heapRedactor;
public void run() {
Tool tool = null;
@@ -123,6 +127,7 @@ public class JMap extends Tool {
public static void main(String[] args) {
int mode = MODE_PMAP;
+ HeapRedactor.RedactParams redactParams = new HeapRedactor.RedactParams();
if (args.length > 1 ) {
String modeFlag = args[0];
boolean copyArgs = true;
@@ -177,6 +182,19 @@ public class JMap extends Tool {
System.err.println("compression level out of range (1-9): " + level);
System.exit(1);
}
+ } else if (keyValue[0].equals("HeapDumpRedact")) {
+ if (!redactParams.setAndCheckHeapDumpRedact(keyValue[1])) {
+ System.exit(1);
+ }
+ } else if (keyValue[0].equals("RedactMap")) {
+ redactParams.setRedactMap(keyValue[1]);
+ } else if (keyValue[0].equals("RedactMapFile")) {
+ redactParams.setRedactMapFile(keyValue[1]);
+ } else if (keyValue[0].equals("RedactClassPath")) {
+ redactParams.setRedactClassPath(keyValue[1]);
+ } else if (keyValue[0].equals("RedactPassword")) {
+ redactParams.setRedactPassword(getRedactPassword());
+
} else {
System.err.println("unknown option:" + keyValue[0]);
@@ -189,12 +207,24 @@ public class JMap extends Tool {
}
}
+ if (redactParams.getHeapDumpRedact() == null) {
+ if (redactParams.getRedactMap() == null && redactParams.getRedactMapFile() == null
+ && redactParams.getRedactClassPath() == null) {
+ redactParams.setEnableRedact(false);
+ } else {
+ System.err.println("Error: HeapDumpRedact must be specified to enable heap-dump-redacting");
+ copyArgs = false;
+ System.exit(1);
+ }
+ }
+
if (copyArgs) {
String[] newArgs = new String[args.length - 1];
for (int i = 0; i < newArgs.length; i++) {
newArgs[i] = args[i + 1];
}
args = newArgs;
+ heapRedactor = new HeapRedactor(redactParams);
}
}
@@ -202,9 +232,39 @@ public class JMap extends Tool {
jmap.execute(args);
}
+ private static CharBuffer getRedactPassword() {
+ CharBuffer redactPassword = CharBuffer.wrap("");
+ // heap dump may need a password
+ Console console = System.console();
+ char[] passwords = null;
+ if (console == null) {
+ return redactPassword;
+ }
+
+ try {
+ passwords = console.readPassword("redact authority password:");
+ } catch (Exception e) {
+ }
+ if(passwords == null) {
+ return redactPassword;
+ }
+
+ try {
+ CharBuffer cb = CharBuffer.wrap(passwords);
+ String passwordPattern = "^[0-9a-zA-Z!@#$]{1,9}$";
+ if(!Pattern.matches(passwordPattern, cb)) {
+ return redactPassword;
+ }
+ redactPassword = cb;
+ } catch (Exception e) {
+ }
+
+ return redactPassword;
+ }
+
public boolean writeHeapHprofBin(String fileName, int gzLevel) {
try {
- HeapGraphWriter hgw;
+ HeapHprofBinWriter hgw;
if (gzLevel == 0) {
hgw = new HeapHprofBinWriter();
} else if (gzLevel >=1 && gzLevel <= 9) {
@@ -213,6 +273,7 @@ public class JMap extends Tool {
System.err.println("Illegal compression level: " + gzLevel);
return false;
}
+ hgw.setHeapRedactor(heapRedactor);
hgw.write(fileName);
System.out.println("heap written to " + fileName);
return true;
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AnnotationArray2D.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AnnotationArray2D.java
new file mode 100644
index 000000000..fa2b06776
--- /dev/null
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AnnotationArray2D.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2023, Huawei Technologies Co., Ltd. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Huawei designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Huawei in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please visit https://gitee.com/openeuler/bishengjdk-8 if you need additional
+ * information or have any questions.
+ */
+
+package sun.jvm.hotspot.utilities;
+
+import sun.jvm.hotspot.debugger.Address;
+import sun.jvm.hotspot.runtime.VM;
+import sun.jvm.hotspot.types.Type;
+import sun.jvm.hotspot.types.TypeDataBase;
+import sun.jvm.hotspot.types.WrongTypeException;
+
+public class AnnotationArray2D extends GenericArray {
+ static {
+ VM.registerVMInitializedObserver(new Observer() {
+ public void update(Observable o, Object data) {
+ initialize(VM.getVM().getTypeDataBase());
+ }
+ });
+ }
+
+ private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
+ elemType = db.lookupType("Array<u1>*");
+
+ Type type = db.lookupType("Array<Array<u1>*>");
+ dataFieldOffset = type.getAddressField("_data").getOffset();
+ }
+
+ private static long dataFieldOffset;
+ protected static Type elemType;
+
+ public AnnotationArray2D(Address addr) {
+ super(addr, dataFieldOffset);
+ }
+
+ public U1Array getAt(int i) {
+ return new U1Array(getAddressAt(i));
+ }
+ public Type getElemType() {
+ return elemType;
+ }
+}
\ No newline at end of file
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java
index c9ffca89e..8501f4d93 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java
@@ -28,6 +28,10 @@ import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.*;
+import java.nio.CharBuffer;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
import java.util.*;
import java.util.zip.*;
import sun.jvm.hotspot.debugger.*;
@@ -36,6 +40,10 @@ import sun.jvm.hotspot.oops.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.classfile.*;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+
import static java.nio.charset.StandardCharsets.UTF_8;
/*
@@ -387,6 +395,71 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
private static final long MAX_U4_VALUE = 0xFFFFFFFFL;
int serialNum = 1;
+ // encrypt
+ private static int SALT_MIN_LENGTH = 8;
+ private static int HASH_BIT_SIZE = 256;
+ private static int HASH_ITERATIONS_COUNT = 10000;
+
+ // Heap Redact
+ private HeapRedactor heapRedactor;
+
+ public HeapRedactor getHeapRedactor() {
+ return heapRedactor;
+ }
+
+ public void setHeapRedactor(HeapRedactor heapRedactor) {
+ this.heapRedactor = heapRedactor;
+ }
+
+ public HeapRedactor.HeapDumpRedactLevel getHeapDumpRedactLevel(){
+ if(heapRedactor==null){
+ return HeapRedactor.HeapDumpRedactLevel.REDACT_OFF;
+ }
+ return heapRedactor.getHeapDumpRedactLevel();
+ }
+
+ public Optional<CharBuffer> getHeapDumpRedactPassword() {
+ return heapRedactor == null ? Optional.empty() : Optional.ofNullable(heapRedactor.getRedactPassword());
+ }
+
+ private Optional<String> lookupRedactName(String name){
+ return heapRedactor == null ? Optional.empty() : heapRedactor.lookupRedactName(name);
+ }
+
+ private void resetRedactParams(){
+ Optional<String> redactOption = getVMRedactParameter("HeapDumpRedact");
+ String redactStr= redactOption.isPresent() ? redactOption.get() : null;
+ if(redactStr!=null && !redactStr.isEmpty()){
+ HeapRedactor.RedactParams redactParams = new HeapRedactor.RedactParams();
+ if(HeapRedactor.REDACT_ANNOTATION_OPTION.equals(redactStr)){
+ Optional<String> classPathOption = getVMRedactParameter("RedactClassPath");
+ String classPathStr = classPathOption.isPresent() ? classPathOption.get() : null;
+ redactStr = classPathOption.isPresent() ? redactStr : HeapRedactor.REDACT_OFF_OPTION;
+ redactParams.setRedactClassPath(classPathStr);
+ } else {
+ Optional<String> redactMapOption = getVMRedactParameter("RedactMap");
+ String redactMapStr = redactMapOption.isPresent() ? redactMapOption.get() : null;
+ redactParams.setRedactMap(redactMapStr);
+ Optional<String> redactMapFileOption = getVMRedactParameter("RedactMapFile");
+ String redactMapFileStr = redactMapFileOption.isPresent() ? redactMapFileOption.get() : null;
+ redactParams.setRedactMapFile(redactMapFileStr);
+ }
+ if(!redactParams.setAndCheckHeapDumpRedact(redactStr)){
+ redactParams.setAndCheckHeapDumpRedact(HeapRedactor.REDACT_OFF_OPTION);
+ }
+ setHeapRedactor(new HeapRedactor(redactParams));
+ }
+ }
+
+ private Optional<String> getVMRedactParameter(String name) {
+ VM vm = VM.getVM();
+ VM.Flag flag = vm.getCommandLineFlag(name);
+ if(flag == null){
+ return Optional.empty();
+ }
+ return Optional.ofNullable(flag.getCcstr());
+ }
+
public HeapHprofBinWriter() {
this.KlassMap = new ArrayList<Klass>();
this.names = new HashSet<Symbol>();
@@ -399,9 +472,69 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
this.gzLevel = gzLevel;
}
+ private boolean checkPassword() {
+ Optional<String> redactAuthOption = getVMRedactParameter("RedactPassword");
+ String redactAuth = redactAuthOption.isPresent() ? redactAuthOption.get() : null;
+ boolean redactAuthFlag = true;
+ if(redactAuth != null) {
+ String[] auths = redactAuth.split(",");
+ if(auths.length != 2) {
+ return redactAuthFlag;
+ }
+
+ Optional<CharBuffer> passwordOption = getHeapDumpRedactPassword();
+ CharBuffer password = passwordOption.isPresent() ? passwordOption.get() : CharBuffer.wrap("");
+ char[] passwordChars = null;
+ try {
+ passwordChars = password.array();
+
+ byte[] saltBytes = auths[1].getBytes("UTF-8");
+ if(saltBytes.length < SALT_MIN_LENGTH) {
+ return redactAuthFlag;
+ }
+
+ String digestStr = getEncryptValue(passwordChars, saltBytes);
+ redactAuthFlag = auths[0].equals(digestStr);
+ } catch (Exception e) {
+ // ignore
+ redactAuthFlag = false;
+ } finally {
+ // clear all password
+ if(passwordChars != null) {
+ Arrays.fill(passwordChars, '0');
+ }
+ }
+ }
+
+ return redactAuthFlag;
+ }
+
+ private String getEncryptValue(char[] passwordValue, byte[] saltBytes) throws InvalidKeySpecException, NoSuchAlgorithmException {
+ StringBuilder digestStrBuilder = new StringBuilder();
+
+ KeySpec spec = new PBEKeySpec(passwordValue, saltBytes, HASH_ITERATIONS_COUNT, HASH_BIT_SIZE);
+ SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
+ SecretKey secretKey = secretKeyFactory.generateSecret(spec);
+ byte[] digestBytes = secretKey.getEncoded();
+ for (byte b : digestBytes) {
+ String hex = Integer.toHexString(0xff & b);
+ if (hex.length() == 1) {
+ digestStrBuilder.append('0');
+ }
+ digestStrBuilder.append(hex);
+ }
+ String digestStr = digestStrBuilder.toString();
+
+ return digestStr;
+ }
+
public synchronized void write(String fileName) throws IOException {
VM vm = VM.getVM();
+ if(getHeapDumpRedactLevel() == HeapRedactor.HeapDumpRedactLevel.REDACT_UNKNOWN || !checkPassword()) {
+ resetRedactParams();
+ }
+
// Check whether we should dump the heap as segments
useSegmentedHeapDump = isCompression() ||
(vm.getUniverse().heap().used() > HPROF_SEGMENTED_HEAP_DUMP_THRESHOLD);
@@ -465,6 +598,9 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
// this will write heap data into the buffer stream
super.write();
+ // write redacted String Field record
+ writeAnnotateFieldValue();
+
// flush buffer stream.
out.flush();
if (!useSegmentedHeapDump) {
@@ -725,6 +861,68 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
}
}
+ private void writeAnnotateFieldValue() throws IOException {
+ HeapRedactor.HeapDumpRedactLevel level = getHeapDumpRedactLevel();
+ if(level != HeapRedactor.HeapDumpRedactLevel.REDACT_ANNOTATION
+ && level != HeapRedactor.HeapDumpRedactLevel.REDACT_DIYRULES) {
+ return;
+ }
+
+ HeapRedactor.RedactVectorNode redactVector = heapRedactor.getHeaderNode();
+ if(redactVector == null) {
+ return;
+ }
+
+ while(redactVector != null) {
+ List<TypeArray> typeArrayList = redactVector.getTypeArrayList();
+ for(int i = 0; i < redactVector.getCurrentIndex(); i++) {
+ TypeArray array = typeArrayList.get(i);
+ TypeArrayKlass tak = (TypeArrayKlass) array.getKlass();
+ final int type = (int) tak.getElementType();
+
+ if(type != TypeArrayKlass.T_BYTE) {
+ continue;
+ }
+
+ OopHandle handle = (array != null)? array.getHandle() : null;
+ long address = getAddressValue(handle);
+ Optional<String> annotateValueOptional = heapRedactor.lookupRedactAnnotationValue(address);
+ String annotateValue = annotateValueOptional.isPresent() ? annotateValueOptional.get() : null;
+ long expectLength = array.getLength();
+ if(annotateValue != null) {
+ expectLength = annotateValue.length();
+ }
+
+ int headerSize = getArrayHeaderSize(false);
+ final String typeName = tak.getElementTypeName();
+ final long typeSize = getSizeForType(type);
+ final int length = calculateArrayMaxLength(expectLength,
+ headerSize,
+ typeSize,
+ typeName);
+ out.writeByte((byte) HPROF_GC_PRIM_ARRAY_DUMP);
+ writeObjectID(array);
+ out.writeInt(DUMMY_STACK_TRACE_ID);
+ out.writeInt(length);
+ out.writeByte((byte) type);
+
+ if (annotateValue != null) {
+ for(int index = 0; index < expectLength; index++) {
+ out.writeByte(annotateValue.charAt(index));
+ }
+ } else {
+ for (int index = 0; index < length; index++) {
+ long offset = BYTE_BASE_OFFSET + index * BYTE_SIZE;
+ out.writeByte(array.getHandle().getJByteAt(offset));
+ }
+ }
+ }
+
+ HeapRedactor.RedactVectorNode tempVector = redactVector.getNext();
+ redactVector = tempVector;
+ }
+ }
+
protected void writeClass(Instance instance) throws IOException {
Klass reflectedKlass = java_lang_Class.asKlass(instance);
// dump instance record only for primitive type Class objects.
@@ -958,9 +1156,18 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
}
protected void writePrimitiveArray(TypeArray array) throws IOException {
+ HeapRedactor.HeapDumpRedactLevel level = getHeapDumpRedactLevel();
+
int headerSize = getArrayHeaderSize(false);
TypeArrayKlass tak = (TypeArrayKlass) array.getKlass();
final int type = tak.getElementType();
+
+ if(type == TypeArrayKlass.T_BYTE && (level == HeapRedactor.HeapDumpRedactLevel.REDACT_ANNOTATION
+ || level == HeapRedactor.HeapDumpRedactLevel.REDACT_DIYRULES)) {
+ heapRedactor.recordTypeArray(array);
+ return;
+ }
+
final String typeName = tak.getElementTypeName();
final long typeSize = getSizeForType(type);
final int length = calculateArrayMaxLength(array.getLength(),
@@ -972,12 +1179,16 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
out.writeInt(DUMMY_STACK_TRACE_ID);
out.writeInt(length);
out.writeByte((byte) type);
+
+ boolean shouldRedact = ( level == HeapRedactor.HeapDumpRedactLevel.REDACT_BASIC
+ || level == HeapRedactor.HeapDumpRedactLevel.REDACT_FULL);
+
switch (type) {
case TypeArrayKlass.T_BOOLEAN:
writeBooleanArray(array, length);
break;
case TypeArrayKlass.T_CHAR:
- writeCharArray(array, length);
+ writeCharArray(array, length, shouldRedact);
break;
case TypeArrayKlass.T_FLOAT:
writeFloatArray(array, length);
@@ -986,13 +1197,13 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
writeDoubleArray(array, length);
break;
case TypeArrayKlass.T_BYTE:
- writeByteArray(array, length);
+ writeByteArray(array, length, shouldRedact);
break;
case TypeArrayKlass.T_SHORT:
writeShortArray(array, length);
break;
case TypeArrayKlass.T_INT:
- writeIntArray(array, length);
+ writeIntArray(array, length, shouldRedact);
break;
case TypeArrayKlass.T_LONG:
writeLongArray(array, length);
@@ -1010,10 +1221,16 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
}
}
- private void writeByteArray(TypeArray array, int length) throws IOException {
- for (int index = 0; index < length; index++) {
- long offset = BYTE_BASE_OFFSET + index * BYTE_SIZE;
- out.writeByte(array.getHandle().getJByteAt(offset));
+ private void writeByteArray(TypeArray array, int length, boolean shouldRedact) throws IOException {
+ if (shouldRedact) {
+ for(int index = 0; index < length; index++) {
+ out.writeByte(0);
+ }
+ } else {
+ for (int index = 0; index < length; index++) {
+ long offset = BYTE_BASE_OFFSET + index * BYTE_SIZE;
+ out.writeByte(array.getHandle().getJByteAt(offset));
+ }
}
}
@@ -1024,10 +1241,16 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
}
}
- private void writeIntArray(TypeArray array, int length) throws IOException {
- for (int index = 0; index < length; index++) {
- long offset = INT_BASE_OFFSET + index * INT_SIZE;
- out.writeInt(array.getHandle().getJIntAt(offset));
+ private void writeIntArray(TypeArray array, int length, boolean shouldRedact) throws IOException {
+ if (shouldRedact) {
+ for(int index = 0; index < length; index++) {
+ out.writeInt(0);
+ }
+ } else {
+ for (int index = 0; index < length; index++) {
+ long offset = INT_BASE_OFFSET + index * INT_SIZE;
+ out.writeInt(array.getHandle().getJIntAt(offset));
+ }
}
}
@@ -1038,10 +1261,16 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
}
}
- private void writeCharArray(TypeArray array, int length) throws IOException {
- for (int index = 0; index < length; index++) {
- long offset = CHAR_BASE_OFFSET + index * CHAR_SIZE;
- out.writeChar(array.getHandle().getJCharAt(offset));
+ private void writeCharArray(TypeArray array, int length, boolean shouldRedact) throws IOException {
+ if (shouldRedact) {
+ for(int index = 0; index < length; index++) {
+ out.writeChar(0);
+ }
+ } else {
+ for (int index = 0; index < length; index++) {
+ long offset = CHAR_BASE_OFFSET + index * CHAR_SIZE;
+ out.writeChar(array.getHandle().getJCharAt(offset));
+ }
}
}
@@ -1083,6 +1312,16 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
for (Iterator<Field> itr = fields.iterator(); itr.hasNext();) {
writeField(itr.next(), instance);
}
+
+ // record the anonymous value for every field
+ if(klass instanceof InstanceKlass && heapRedactor != null) {
+ if(heapRedactor.getHeapDumpRedactLevel() == HeapRedactor.HeapDumpRedactLevel.REDACT_ANNOTATION
+ && heapRedactor.getRedactAnnotationClassPath() != null && !heapRedactor.getRedactAnnotationClassPath().isEmpty()) {
+ recordAnnotationValueMap(fields, instance);
+ } else if( heapRedactor.getHeapDumpRedactLevel() == HeapRedactor.HeapDumpRedactLevel.REDACT_DIYRULES) {
+ recordDiyRulesValueMap(fields, instance);
+ }
+ }
}
//-- Internals only below this point
@@ -1105,6 +1344,131 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
}
}
+ private void recordAnnotationValueMap(List<Field> fields, Instance instance) {
+ Klass klass = instance.getKlass();
+ boolean inJavaPackage = false;
+ Symbol classNameSymbol = klass.getName();
+ if(classNameSymbol != null) {
+ String className = classNameSymbol.asString();
+ inJavaPackage = (className != null && className.startsWith("java/"));
+ }
+ if(inJavaPackage){
+ return;
+ }
+ for (Field field : fields) {
+ Symbol fieldSignature = field.getSignature();
+ if(fieldSignature == null || fieldSignature.asString() == null
+ || !"Ljava/lang/String;".equals(fieldSignature.asString())) {
+ continue;
+ }
+ try {
+ InstanceKlass fieldHolder = field.getFieldHolder();
+ U1Array fieldAnnotations = field.getFieldAnnotations();
+ Optional<String> anonymousValueOption = getAnonymousValue(fieldAnnotations, fieldHolder.getConstants());
+ if(!anonymousValueOption.isPresent()) {
+ continue;
+ }
+ long address = getStringFieldAddress(field, instance);
+ if(address > 0L) {
+ heapRedactor.recordRedactAnnotationValue(address, anonymousValueOption.get());
+ }
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ private Optional<String> getAnonymousValue(U1Array fieldAnnotations, ConstantPool cp) {
+ Optional<String> anonymousValueOption = Optional.empty();
+ if (fieldAnnotations.getAddress() == null) {
+ return anonymousValueOption;
+ }
+
+ int fieldAnnotationsTagsLen = fieldAnnotations.length();
+ boolean isAnonymousAnnotation = false;
+ int annotationStart = 0;
+ int annotationEnd = 0;
+ for (int j = 0; j < fieldAnnotationsTagsLen; j++) {
+ int cpIndex = fieldAnnotations.at(j);
+ if (cpIndex >= cp.getLength() || cpIndex < 0) {
+ continue;
+ }
+ byte cpConstType = cp.getTags().at(cpIndex);
+ if (cpConstType == ConstantPool.JVM_CONSTANT_Utf8) {
+ annotationStart += (isAnonymousAnnotation ? 0 : 1);
+ annotationEnd++;
+ Symbol symbol = cp.getSymbolAt(cpIndex);
+ if (symbol.asString() == null || symbol.asString().isEmpty()) {
+ continue;
+ }
+ if (symbol.asString().equals("L" + heapRedactor.getRedactAnnotationClassPath() + ";")) {
+ isAnonymousAnnotation = true;
+ }
+ if(annotationEnd - annotationStart == 1 && !"value".equals(symbol.asString())) {
+ break;
+ }
+ if(annotationEnd - annotationStart == 2) {
+ anonymousValueOption = Optional.ofNullable(cp.getSymbolAt(cpIndex).asString());
+ break;
+ }
+ }
+ }
+ return anonymousValueOption;
+ }
+
+ private void recordDiyRulesValueMap(List<Field> fields, Instance instance) {
+ Klass klass = instance.getKlass();
+ boolean diyRulesFlag = false;
+ Symbol classNameSymbol = klass.getName();
+ Map<String, String> redactRulesMap = null;
+ if(classNameSymbol != null) {
+ String className = classNameSymbol.asString();
+ Optional<Map<String, String>> redactRulesMapOptional = className == null ? Optional.empty() : heapRedactor.getRedactRulesTable(className);
+ redactRulesMap = redactRulesMapOptional.isPresent() ? redactRulesMapOptional.get() : null;
+ diyRulesFlag = (redactRulesMap != null);
+ }
+ if(!diyRulesFlag){
+ return;
+ }
+ for (Field field : fields) {
+ Symbol fieldSignature = field.getSignature();
+ if(fieldSignature == null || fieldSignature.asString() == null || !"Ljava/lang/String;".equals(fieldSignature.asString())) {
+ continue;
+ }
+
+ try {
+ Symbol filedNameSymbol = field.getName();
+ if(filedNameSymbol == null) {
+ continue;
+ }
+
+ String filedName = filedNameSymbol.asString();
+ String replaceValue = filedName == null ? null : redactRulesMap.get(filedName);
+ long address = getStringFieldAddress(field, instance);
+ if(address > 0L && replaceValue != null) {
+ heapRedactor.recordRedactAnnotationValue(address, replaceValue);
+ }
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ private long getStringFieldAddress(Field field, Instance instance) {
+ long address = 0L;
+ if(field instanceof OopField) {
+ Oop fieldOop = ((OopField) field).getValue(instance);
+ Field stringField = null;
+ if (fieldOop != null && fieldOop.getKlass() instanceof InstanceKlass) {
+ List<Field> oopFiledSubs = ((InstanceKlass) fieldOop.getKlass()).getAllFields();
+ stringField = oopFiledSubs.iterator().next();
+ }
+ if (stringField != null && stringField instanceof OopField) {
+ OopHandle handle = ((OopField) stringField).getValueAsOopHandle(fieldOop);
+ address = getAddressValue(handle);
+ }
+ }
+ return address;
+ }
+
public static int signatureToHprofKind(char ch) {
switch (ch) {
case JVM_SIGNATURE_CLASS:
@@ -1221,7 +1585,18 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
// If name is already written don't write it again.
if (names.add(sym)) {
if(sym != null) {
- byte[] buf = sym.asString().getBytes(UTF_8);
+ String symbolStr = sym.asString();
+ HeapRedactor.HeapDumpRedactLevel level = getHeapDumpRedactLevel();
+ boolean shouldRedact = (level == HeapRedactor.HeapDumpRedactLevel.REDACT_NAMES ||
+ level == HeapRedactor.HeapDumpRedactLevel.REDACT_FULL);
+ byte[] buf = null;
+ if(shouldRedact) {
+ Optional<String> redactField = lookupRedactName(symbolStr);
+ buf = redactField.isPresent() ? redactField.get().getBytes("UTF-8") : null;
+ }
+ if(buf == null) {
+ buf = symbolStr.getBytes(UTF_8);
+ }
writeHeader(HPROF_UTF8, buf.length + OBJ_ID_SIZE);
writeSymbolID(sym);
out.write(buf);
@@ -1301,11 +1676,23 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
List<Field> res = new ArrayList<>();
while (klass != null) {
List<Field> curFields = klass.getImmediateFields();
+ Annotation annotation = klass.getAnnotation();
+ AnnotationArray2D fieldsAnnotations = (annotation == null) ? null : annotation.getFieldsAnnotations();
+ boolean hasAnnotations = false;
+ if(fieldsAnnotations != null && fieldsAnnotations.getAddress() != null) {
+ hasAnnotations = true;
+ }
+ int fieldIndex = 0;
for (Iterator<Field> itr = curFields.iterator(); itr.hasNext();) {
Field f = itr.next();
if (! f.isStatic()) {
res.add(f);
+ // record annotation for class Field
+ if(hasAnnotations) {
+ f.setFieldAnnotations(fieldsAnnotations.getAt(fieldIndex));
+ }
}
+ fieldIndex++;
}
klass = (InstanceKlass) klass.getSuper();
}
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapRedactor.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapRedactor.java
new file mode 100644
index 000000000..5c442b2bb
--- /dev/null
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapRedactor.java
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2023, Huawei Technologies Co., Ltd. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Huawei designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Huawei in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please visit https://gitee.com/openeuler/bishengjdk-8 if you need additional
+ * information or have any questions.
+ */
+
+package sun.jvm.hotspot.utilities;
+
+import sun.jvm.hotspot.oops.TypeArray;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.nio.CharBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Locale;
+import java.util.Optional;
+
+public class HeapRedactor {
+ public enum HeapDumpRedactLevel {
+ REDACT_UNKNOWN,
+ REDACT_OFF,
+ REDACT_NAMES,
+ REDACT_BASIC,
+ REDACT_DIYRULES,
+ REDACT_ANNOTATION,
+ REDACT_FULL
+ }
+
+ private HeapDumpRedactLevel redactLevel;
+ private Map<String, String> redactNameTable;
+ private Map<String, Map<String, String>> redactClassTable;
+ private String redactClassFullName = null;
+ private Map<Long, String> redactValueTable;
+ private RedactVectorNode headerNode;
+ private RedactVectorNode currentNode;
+
+ private RedactParams redactParams;
+
+ public static final String HEAP_DUMP_REDACT_PREFIX = "HeapDumpRedact=";
+ public static final String REDACT_MAP_PREFIX = "RedactMap=";
+ public static final String REDACT_MAP_FILE_PREFIX = "RedactMapFile=";
+ public static final String REDACT_CLASS_PATH_PREFIX = "RedactClassPath=";
+ public static final String REDACT_PASSWORD_PREFIX = "RedactPassword=";
+
+ public static final String REDACT_UNKNOWN_STR = "UNKNOWN";
+ public static final String REDACT_OFF_STR = "OFF";
+ public static final String REDACT_NAME_STR = "NAMES";
+ public static final String REDACT_BASIC_STR = "BASIC";
+ public static final String REDACT_DIYRULES_STR = "DIYRULES";
+ public static final String REDACT_ANNOTATION_STR = "ANNOTATION";
+ public static final String REDACT_FULL_STR = "FULL";
+
+ public static final String REDACT_UNKNOWN_OPTION = REDACT_UNKNOWN_STR.toLowerCase(Locale.ROOT);
+ public static final String REDACT_OFF_OPTION = REDACT_OFF_STR.toLowerCase(Locale.ROOT);
+ public static final String REDACT_NAME_OPTION = REDACT_NAME_STR.toLowerCase(Locale.ROOT);
+ public static final String REDACT_BASIC_OPTION = REDACT_BASIC_STR.toLowerCase(Locale.ROOT);
+ public static final String REDACT_DIYRULES_OPTION = REDACT_DIYRULES_STR.toLowerCase(Locale.ROOT);
+ public static final String REDACT_ANNOTATION_OPTION = REDACT_ANNOTATION_STR.toLowerCase(Locale.ROOT);
+ public static final String REDACT_FULL_OPTION = REDACT_FULL_STR.toLowerCase(Locale.ROOT);
+
+ public static final int PATH_MAX = 4096;
+ public static final int REDACT_VECTOR_SIZE = 1024;
+
+ public HeapRedactor(RedactParams redactParams) {
+ this.redactParams = redactParams;
+ redactLevel = HeapDumpRedactLevel.REDACT_UNKNOWN;
+ redactNameTable = null;
+ redactClassTable = null;
+ redactValueTable = null;
+ init(null);
+ }
+
+ private void init(String options) {
+ if (redactLevel == HeapDumpRedactLevel.REDACT_UNKNOWN) {
+ initHeapdumpRedactLevel(options);
+ }
+ }
+
+ public HeapDumpRedactLevel getHeapDumpRedactLevel() {
+ return redactLevel;
+ }
+
+ public String getRedactLevelString() {
+ switch (redactLevel) {
+ case REDACT_BASIC:
+ return REDACT_BASIC_STR;
+ case REDACT_NAMES:
+ return REDACT_NAME_STR;
+ case REDACT_FULL:
+ return REDACT_FULL_STR;
+ case REDACT_DIYRULES:
+ return REDACT_DIYRULES_STR;
+ case REDACT_ANNOTATION:
+ return REDACT_ANNOTATION_STR;
+ case REDACT_OFF:
+ return REDACT_OFF_STR;
+ case REDACT_UNKNOWN:
+ default:
+ return REDACT_UNKNOWN_STR;
+ }
+ }
+
+ public Optional<String> lookupRedactName(String name){
+ return Optional.ofNullable(redactNameTable == null ? null : redactNameTable.get(name));
+ }
+
+ public void recordTypeArray(TypeArray oop) {
+ int tmp_index = currentNode.getCurrentIndex();
+ if(tmp_index == REDACT_VECTOR_SIZE){
+ RedactVectorNode newNode = new RedactVectorNode();
+ List<TypeArray> list = new ArrayList<>(REDACT_VECTOR_SIZE);
+ newNode.setTypeArrayList(list);
+ newNode.setNext(null);
+ newNode.setCurrentIndex(0);
+ tmp_index = 0;
+ currentNode.setNext(newNode);
+ currentNode = newNode;
+ }
+ currentNode.getTypeArrayList().add(tmp_index, oop);
+ tmp_index++;
+ currentNode.setCurrentIndex(tmp_index);
+
+ }
+
+ public RedactVectorNode getHeaderNode(){
+ return headerNode;
+ }
+
+ public void recordRedactAnnotationValue(Long addr, String value) {
+ redactValueTable.put(addr, value);
+ }
+
+ public Optional<String> lookupRedactAnnotationValue(Long addr){
+ return Optional.ofNullable(redactValueTable == null ? null : redactValueTable.get(addr));
+ }
+
+ public String getRedactAnnotationClassPath(){
+ return redactParams.getRedactClassPath();
+ }
+
+ public CharBuffer getRedactPassword(){
+ return redactParams.getRedactPassword();
+ }
+
+ public Optional<Map<String, String>> getRedactRulesTable(String key) {
+ return Optional.ofNullable(redactClassTable == null ? null: redactClassTable.get(key));
+ }
+
+ private HeapDumpRedactLevel initHeapdumpRedactLevel(String options) {
+ RedactParams customizedParams = parseRedactOptions(options);
+
+ if (customizedParams.isEnableRedact() || this.redactParams == null) {
+ this.redactParams = customizedParams;
+ }
+
+ if (redactParams.heapDumpRedact == null) {
+ redactLevel = HeapDumpRedactLevel.REDACT_UNKNOWN;
+ } else {
+ if (REDACT_BASIC_OPTION.equals(redactParams.heapDumpRedact)) {
+ redactLevel = HeapDumpRedactLevel.REDACT_BASIC;
+ } else if (REDACT_NAME_OPTION.equals(redactParams.heapDumpRedact)) {
+ redactLevel = HeapDumpRedactLevel.REDACT_NAMES;
+ initRedactMap();
+ } else if (REDACT_FULL_OPTION.equals(redactParams.heapDumpRedact)) {
+ redactLevel = HeapDumpRedactLevel.REDACT_FULL;
+ initRedactMap();
+ } else if (REDACT_DIYRULES_OPTION.equals(redactParams.heapDumpRedact)) {
+ redactLevel = HeapDumpRedactLevel.REDACT_DIYRULES;
+ initRedactMap();
+ initRedactVector();
+ } else if (REDACT_ANNOTATION_OPTION.equals(redactParams.heapDumpRedact)) {
+ redactLevel = HeapDumpRedactLevel.REDACT_ANNOTATION;
+ initRedactVector();
+ } else {
+ redactLevel = HeapDumpRedactLevel.REDACT_OFF;
+ }
+ }
+ return redactLevel;
+ }
+
+ private void initRedactVector(){
+ if(redactValueTable == null) {
+ redactValueTable = new HashMap<>();
+ }
+ if(headerNode == null) {
+ headerNode = new RedactVectorNode();
+ List<TypeArray> list = new ArrayList<>(REDACT_VECTOR_SIZE);
+ headerNode.setTypeArrayList(list);
+ headerNode.setNext(null);
+ headerNode.setCurrentIndex(0);
+ currentNode = headerNode;
+ }
+ }
+
+ private RedactParams parseRedactOptions(String optionStr) {
+ RedactParams params = new RedactParams(REDACT_OFF_OPTION, null, null, null, null);
+ if (optionStr != null) {
+ String[] options = optionStr.split(",");
+ for (String option : options) {
+ if (option.startsWith(HEAP_DUMP_REDACT_PREFIX)) {
+ params.setAndCheckHeapDumpRedact(option.substring(HEAP_DUMP_REDACT_PREFIX.length()));
+ } else if (option.startsWith(REDACT_MAP_PREFIX)) {
+ params.setRedactMap(option.substring(REDACT_MAP_PREFIX.length()));
+ } else if (option.startsWith(REDACT_MAP_FILE_PREFIX)) {
+ params.setRedactMapFile(option.substring(REDACT_MAP_FILE_PREFIX.length()));
+ } else if (option.startsWith(REDACT_CLASS_PATH_PREFIX)) {
+ params.setRedactClassPath(option.substring(REDACT_CLASS_PATH_PREFIX.length()));
+ } else {
+ continue;
+ }
+ }
+ }
+ return params;
+ }
+
+ private void initRedactMap() {
+ if (redactParams.redactMapFile != null) {
+ readRedactMapFromFile(redactParams.redactMapFile);
+ }
+ if (redactParams.redactMap != null) {
+ parseRedactMapStringDependOnMode(redactParams.redactMap, redactLevel);
+ }
+ }
+
+ private void readRedactMapFromFile(String path) {
+ if (path == null || path.isEmpty()) {
+ // RedactMapFile=<file> not specified
+ return;
+ } else {
+ if (path.length() >= PATH_MAX) {
+ System.err.println("RedactMap File path is too long");
+ return;
+ }
+ File file = new File(path);
+ if (!file.exists() || !file.isFile()) {
+ System.err.println("RedactMap File does not exist");
+ }
+ try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ parseRedactMapStringDependOnMode(line, redactLevel);
+ }
+ } catch (IOException e) {
+ System.err.println("Encounter an error when reading " + path + " , skip processing RedactMap File.");
+ e.printStackTrace();
+ return;
+ }
+ }
+ }
+
+ private void parseRedactMapStringDependOnMode(String nameMapList, HeapDumpRedactLevel redactLevel) {
+ if(redactLevel == HeapDumpRedactLevel.REDACT_DIYRULES) {
+ parseRedactDiyRulesString(nameMapList);
+ } else {
+ parseRedactMapString(nameMapList);
+ }
+ }
+
+ private void parseRedactMapString(String nameMapList) {
+ if (redactNameTable == null) {
+ redactNameTable = new HashMap<>();
+ }
+ String[] tokens = nameMapList.split("[,;\\s+]");
+ for (String token : tokens) {
+ String[] pair = token.split(":");
+ if (pair.length == 2) {
+ redactNameTable.put(pair[0], pair[1]);
+ }
+ }
+ }
+
+ private void parseRedactDiyRulesString(String nameMapList) {
+ if (redactClassTable == null) {
+ redactClassTable = new HashMap<>();
+ }
+ Map<String, String> redactRulesTable = redactClassFullName == null ? null : redactClassTable.get(redactClassFullName);
+ String[] tokens = nameMapList.split("[,;\\s+]");
+ for (String token : tokens) {
+ String[] pair = token.split(":");
+ if (pair.length == 1) {
+ redactClassFullName = pair[0].replace(".", "/");
+ redactRulesTable = redactClassTable.get(redactClassFullName);
+ if(redactRulesTable == null) {
+ redactRulesTable = new HashMap<>();
+ redactClassTable.put(redactClassFullName, redactRulesTable);
+ }
+ }
+ if (pair.length == 2 && redactRulesTable != null) {
+ redactRulesTable.put(pair[0], pair[1]);
+ }
+ }
+ }
+
+ public static class RedactParams {
+ private String heapDumpRedact;
+ private String redactMap;
+ private String redactMapFile;
+ private String redactClassPath;
+ private CharBuffer redactPassword;
+ private boolean enableRedact = false;
+
+ public RedactParams() {
+ }
+
+ public RedactParams(String heapDumpRedact, String redactMap, String redactMapFile, String redactClassPath, CharBuffer redactPassword) {
+ this.heapDumpRedact = heapDumpRedact;
+ this.redactMap = redactMap;
+ this.redactMapFile = redactMapFile;
+ this.redactClassPath = redactClassPath;
+ this.redactPassword = redactPassword;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ if (heapDumpRedact != null) {
+ builder.append(HEAP_DUMP_REDACT_PREFIX);
+ builder.append(heapDumpRedact);
+ builder.append(",");
+ }
+ if (redactMap != null) {
+ builder.append(REDACT_MAP_PREFIX);
+ builder.append(redactMap);
+ builder.append(",");
+ }
+ if (redactMapFile != null) {
+ builder.append(REDACT_MAP_FILE_PREFIX);
+ builder.append(redactMapFile);
+ builder.append(",");
+ }
+ if (redactClassPath != null) {
+ builder.append(REDACT_CLASS_PATH_PREFIX);
+ builder.append(redactClassPath);
+ }
+ return builder.toString();
+ }
+
+ public String getHeapDumpRedact() {
+ return heapDumpRedact;
+ }
+
+ public boolean setAndCheckHeapDumpRedact(String heapDumpRedact) {
+ if (!checkLauncherHeapdumpRedactSupport(heapDumpRedact)) {
+ return false;
+ }
+ this.heapDumpRedact = heapDumpRedact;
+ this.enableRedact = true;
+ return true;
+ }
+
+ public String getRedactMap() {
+ return redactMap;
+ }
+
+ public void setRedactMap(String redactMap) {
+ this.redactMap = redactMap;
+ }
+
+ public String getRedactMapFile() {
+ return redactMapFile;
+ }
+
+ public void setRedactMapFile(String redactMapFile) {
+ this.redactMapFile = redactMapFile;
+ }
+
+ public String getRedactClassPath() {
+ return redactClassPath;
+ }
+
+ public void setRedactClassPath(String redactClassPath) {
+ this.redactClassPath = redactClassPath;
+ }
+
+ public CharBuffer getRedactPassword() {
+ return redactPassword;
+ }
+
+ public void setRedactPassword(CharBuffer redactPassword) {
+ this.redactPassword = redactPassword;
+ }
+
+ public static boolean checkLauncherHeapdumpRedactSupport(String value) {
+ String[] validValues = {REDACT_BASIC_OPTION, REDACT_NAME_OPTION, REDACT_FULL_OPTION, REDACT_DIYRULES_OPTION, REDACT_ANNOTATION_OPTION, REDACT_OFF_OPTION};
+ for (String validValue : validValues) {
+ if (validValue.equals(value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isEnableRedact() {
+ return enableRedact;
+ }
+
+ public void setEnableRedact(boolean enableRedact) {
+ this.enableRedact = enableRedact;
+ }
+ }
+
+ public class RedactVectorNode{
+ private List<TypeArray> typeArrayList;
+ private RedactVectorNode next;
+ private int currentIndex;
+
+ public List<TypeArray> getTypeArrayList() {
+ return typeArrayList;
+ }
+
+ public void setTypeArrayList(List<TypeArray> list) {
+ this.typeArrayList = list;
+ }
+
+ public RedactVectorNode getNext() {
+ return next;
+ }
+
+ public void setNext(RedactVectorNode next) {
+ this.next = next;
+ }
+
+ public int getCurrentIndex() {
+ return currentIndex;
+ }
+
+ public void setCurrentIndex(int index) {
+ this.currentIndex = index;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java b/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java
index 8939d6093..50757d2d7 100644
--- a/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java
+++ b/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java
@@ -25,16 +25,29 @@
package sun.tools.jmap;
+import java.io.BufferedInputStream;
+import java.io.Console;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.CharBuffer;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.regex.Pattern;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.AttachNotSupportedException;
import sun.tools.attach.HotSpotVirtualMachine;
import sun.tools.common.ProcessArgumentMatcher;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+
import static java.nio.charset.StandardCharsets.UTF_8;
/*
@@ -45,6 +58,10 @@ import static java.nio.charset.StandardCharsets.UTF_8;
* options are mapped to SA tools.
*/
public class JMap {
+ // encrypt
+ private static int SALT_MIN_LENGTH = 8;
+ private static int HASH_BIT_SIZE = 256;
+ private static int HASH_ITERATIONS_COUNT = 10000;
public static void main(String[] args) throws Exception {
if (args.length == 0) {
@@ -206,6 +223,8 @@ public class JMap {
String filename = null;
String liveopt = "-all";
String compress_level = null;
+ RedactParams redactParams = new RedactParams();
+ String redactPassword = ",RedactPassword=";
for (String subopt : subopts) {
if (subopt.equals("") || subopt.equals("all")) {
@@ -226,6 +245,18 @@ public class JMap {
System.err.println("Fail: no number provided in option: '" + subopt + "'");
usage(1);
}
+ } else if (subopt.startsWith("HeapDumpRedact=")) {
+ if (!redactParams.setAndCheckHeapDumpRedact(subopt.substring("HeapDumpRedact=".length()))) {
+ usage(1);
+ }
+ } else if (subopt.startsWith("RedactMap=")) {
+ redactParams.setRedactMap(subopt.substring("RedactMap=".length()));
+ } else if (subopt.startsWith("RedactMapFile=")) {
+ redactParams.setRedactMapFile(subopt.substring("RedactMapFile=".length()));
+ } else if (subopt.startsWith("RedactClassPath")) {
+ redactParams.setRedactClassPath(subopt.substring("RedactClassPath=".length()));
+ } else if (subopt.startsWith("RedactPassword")) {
+ redactPassword = getRedactPassword(pid);
} else {
System.err.println("Fail: invalid option: '" + subopt + "'");
usage(1);
@@ -237,10 +268,121 @@ public class JMap {
usage(1);
}
+ checkRedactParams(redactParams);
+
System.out.flush();
// dumpHeap is not the same as jcmd GC.heap_dump
- executeCommandForPid(pid, "dumpheap", filename, liveopt, compress_level);
+ String heapDumpRedactParams = redactParams.isEnableRedact() ? ";" + redactParams.toDumpArgString() + redactPassword : "";
+ executeCommandForPid(pid, "dumpheap", filename + heapDumpRedactParams, liveopt, compress_level);
+ }
+
+ private static void checkRedactParams(RedactParams redactParams) {
+ if (redactParams.getHeapDumpRedact() == null) {
+ if (redactParams.getRedactMap() == null && redactParams.getRedactMapFile() == null) {
+ redactParams.setEnableRedact(false);
+ } else {
+ System.err.println("Error: HeapDumpRedact must be specified to enable heap-dump-redacting");
+ usage(1);
+ }
+ }
+ }
+
+ private static String getRedactPassword(String pid) {
+ String redactPassword = ",RedactPassword=";
+ // heap dump may need a password
+ Console console = System.console();
+ char[] passwords = null;
+ if (console == null) {
+ return redactPassword;
+ }
+
+ try {
+ passwords = console.readPassword("redact authority password:");
+ } catch (Exception e) {
+ }
+ if(passwords == null) {
+ return redactPassword;
+ }
+
+ String digestStr = null;
+ try {
+ CharBuffer cb = CharBuffer.wrap(passwords);
+ String passwordPattern = "^[0-9a-zA-Z!@#$]{1,9}$";
+ if(!Pattern.matches(passwordPattern, cb)) {
+ return redactPassword;
+ }
+
+ String salt = getSalt(pid);
+ if(salt == null) {
+ return redactPassword;
+ }
+ byte[] saltBytes = salt.getBytes("UTF-8");
+ if(saltBytes.length < SALT_MIN_LENGTH) {
+ return redactPassword;
+ }
+ digestStr = getEncryptValue(passwords, saltBytes);
+ } catch (Exception e) {
+ }finally {
+ // clear all password
+ if(passwords != null) {
+ Arrays.fill(passwords, '0');
+ }
+ }
+
+ redactPassword += (digestStr == null ? "" : digestStr);
+ return redactPassword;
+ }
+
+ private static String getSalt(String pid) throws Exception {
+ String salt = null;
+ StringBuilder redactAuth = new StringBuilder();
+
+ VirtualMachine vm = VirtualMachine.attach(pid);
+ HotSpotVirtualMachine hvm = (HotSpotVirtualMachine) vm;
+ String flag = "RedactPassword";
+ try (InputStream in = hvm.printFlag(flag); BufferedInputStream bis = new BufferedInputStream(in);
+ InputStreamReader isr = new InputStreamReader(bis, "UTF-8")) {
+ char c[] = new char[256];
+ int n;
+ do {
+ n = isr.read(c);
+
+ if (n > 0) {
+ redactAuth.append(n == c.length ? c : Arrays.copyOf(c, n));
+ }
+ } while (n > 0);
+ }
+ vm.detach();
+
+ if(redactAuth.length() > 0) {
+ String[] auths = redactAuth.toString().split(",");
+ if(auths.length != 2) {
+ return salt;
+ }
+ return auths[1].trim();
+ }
+
+ return salt;
+ }
+
+ private static String getEncryptValue(char[] passwordValue, byte[] saltBytes) throws InvalidKeySpecException, NoSuchAlgorithmException {
+ StringBuilder digestStrBuilder = new StringBuilder();
+
+ KeySpec spec = new PBEKeySpec(passwordValue, saltBytes, HASH_ITERATIONS_COUNT, HASH_BIT_SIZE);
+ SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
+ SecretKey secretKey = secretKeyFactory.generateSecret(spec);
+ byte[] digestBytes = secretKey.getEncoded();
+ for (byte b : digestBytes) {
+ String hex = Integer.toHexString(0xff & b);
+ if (hex.length() == 1) {
+ digestStrBuilder.append('0');
+ }
+ digestStrBuilder.append(hex);
+ }
+ String digestStr = digestStrBuilder.toString();
+
+ return digestStr;
}
private static void checkForUnsupportedOptions(String[] args) {
@@ -307,6 +449,12 @@ public class JMap {
System.err.println(" file=<file> dump heap to <file>");
System.err.println(" gz=<number> If specified, the heap dump is written in gzipped format using the given compression level.");
System.err.println(" 1 (recommended) is the fastest, 9 the strongest compression.");
+ System.err.println(" HeapDumpRedact=<basic|names|full|diyrules|annotation|off> redact the heapdump information to remove sensitive data,");
+ System.err.println(" RedactMap=<name1:value1;name2:value2;...> Redact the class and field names to other strings");
+ System.err.println(" RedactMapFile=<file> file path of the redact map");
+ System.err.println(" RedactClassPath=<classpath> full path of the redact annotation");
+ System.err.println(" RedactPassword maybe redact feature has an authority, will wait for a password, ");
+ System.err.println(" without a correct password, heap dump with default redact level");
System.err.println("");
System.err.println(" Example: jmap -dump:live,format=b,file=heap.bin <pid>");
System.err.println("");
@@ -322,4 +470,112 @@ public class JMap {
System.err.println(" Example: jmap -histo:live,file=/tmp/histo.data <pid>");
System.exit(exit);
}
+
+ public static class RedactParams {
+ private boolean enableRedact = false;
+ private String heapDumpRedact;
+ private String redactMap;
+ private String redactMapFile;
+ private String redactClassPath;
+
+ public RedactParams() {
+ }
+
+ public RedactParams(String heapDumpRedact, String redactMap, String redactMapFile, String redactClassPath) {
+ if (heapDumpRedact != null && checkLauncherHeapdumpRedactSupport(heapDumpRedact)) {
+ enableRedact = true;
+ }
+ this.heapDumpRedact = heapDumpRedact;
+ this.redactMap = redactMap;
+ this.redactMapFile = redactMapFile;
+ this.redactClassPath = redactClassPath;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ if (heapDumpRedact != null) {
+ builder.append("HeapDumpRedact=");
+ builder.append(heapDumpRedact);
+ builder.append(",");
+ }
+ if (redactMap != null) {
+ builder.append("RedactMap=");
+ builder.append(redactMap);
+ builder.append(",");
+ }
+ if (redactMapFile != null) {
+ builder.append("RedactMapFile=");
+ builder.append(redactMapFile);
+ builder.append(",");
+ }
+ if (redactClassPath != null) {
+ builder.append("RedactClassPath=");
+ builder.append(redactClassPath);
+ }
+ return builder.toString();
+ }
+
+ public String toDumpArgString() {
+ return "-HeapDumpRedact=" + (heapDumpRedact == null ? "off" : heapDumpRedact) +
+ ",RedactMap=" + (redactMap == null ? "" : redactMap) +
+ ",RedactMapFile=" + (redactMapFile == null ? "" : redactMapFile) +
+ ",RedactClassPath=" + (redactClassPath == null ? "" : redactClassPath);
+ }
+
+ public static boolean checkLauncherHeapdumpRedactSupport(String value) {
+ String[] validValues = {"basic", "names", "full", "diyrules", "annotation", "off"};
+ for (String validValue : validValues) {
+ if (validValue.equals(value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isEnableRedact() {
+ return enableRedact;
+ }
+
+ public void setEnableRedact(boolean enableRedact) {
+ this.enableRedact = enableRedact;
+ }
+
+ public String getHeapDumpRedact() {
+ return heapDumpRedact;
+ }
+
+ public boolean setAndCheckHeapDumpRedact(String heapDumpRedact) {
+ if (!checkLauncherHeapdumpRedactSupport(heapDumpRedact)) {
+ return false;
+ }
+ this.heapDumpRedact = heapDumpRedact;
+ this.enableRedact = true;
+ return true;
+ }
+
+ public String getRedactMap() {
+ return redactMap;
+ }
+
+ public void setRedactMap(String redactMap) {
+ this.redactMap = redactMap;
+ }
+
+ public String getRedactMapFile() {
+ return redactMapFile;
+ }
+
+ public void setRedactMapFile(String redactMapFile) {
+ this.redactMapFile = redactMapFile;
+ }
+
+ public String getRedactClassPath() {
+ return redactClassPath;
+ }
+
+ public void setRedactClassPath(String redactClassPath) {
+ this.redactClassPath = redactClassPath;
+ }
+ }
}
--
2.47.0.windows.2
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/zhangyunbo7/openjdk-21.git
git@gitee.com:zhangyunbo7/openjdk-21.git
zhangyunbo7
openjdk-21
openjdk-21
openEuler-24.03-LTS

搜索帮助