From 263784e682e1802e1d90121df51768efcb4db5d2 Mon Sep 17 00:00:00 2001 From: ghidragon <106987263+ghidragon@users.noreply.github.com> Date: Thu, 2 Apr 2026 12:10:34 -0400 Subject: [PATCH] GP-6453 Added interactive dialog for merging structures. --- Ghidra/Features/Base/certification.manifest | 2 + .../Base/data/base.icons.theme.properties | 2 +- .../Features/Base/data/base.theme.properties | 5 +- .../data_type_manager_description.htm | 70 +- .../images/DataTypeTreeWithAssociations.png | Bin 0 -> 18347 bytes .../images/MergeConfirmationDialog.png | Bin 19846 -> 11399 bytes .../images/MergeErrorDialog.png | Bin 13635 -> 8644 bytes .../images/StructureMergeDialog.png | Bin 0 -> 17116 bytes .../app/merge/structures/ComparisonItem.java | 181 +++++ .../structures/ComparisonItemLayout.java | 149 ++++ .../structures/ComparisonItemRenderer.java | 191 ++++++ .../CoordinatedStructureDisplay.java | 231 +++++++ .../structures/CoordinatedStructureLine.java | 83 +++ .../structures/CoordinatedStructureModel.java | 474 +++++++++++++ .../merge/structures/DisplayCoordinator.java | 88 +++ .../merge/structures/StructDisplayModel.java | 78 +++ .../structures/StructureComponentLine.java | 444 ++++++++++++ .../structures/StructureDescriptionLine.java | 158 +++++ .../merge/structures/StructureInfoLine.java | 116 ++++ .../structures/StructureMergeDialog.java | 420 ++++++++++++ .../merge/structures/StructureNameLine.java | 165 +++++ .../datamgr/actions/MergeDataTypeAction.java | 50 +- .../CoordinatedStructureModelTest.java | 642 ++++++++++++++++++ .../database/data/merge/DataTypeMerger.java | 9 +- .../database/data/merge/StructureMerger.java | 164 ++++- .../program/model/data/BitFieldDataType.java | 45 ++ .../database/data/merge/StructureBuilder.java | 80 +++ .../data/merge/StructureMergerTest.java | 455 ++++++++----- .../src/main/java/utility/function/Dummy.java | 14 +- .../DataTypeManagerPluginScreenShots.java | 51 +- 30 files changed, 4120 insertions(+), 247 deletions(-) create mode 100644 Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/images/DataTypeTreeWithAssociations.png create mode 100644 Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/images/StructureMergeDialog.png create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/merge/structures/ComparisonItem.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/merge/structures/ComparisonItemLayout.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/merge/structures/ComparisonItemRenderer.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/merge/structures/CoordinatedStructureDisplay.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/merge/structures/CoordinatedStructureLine.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/merge/structures/CoordinatedStructureModel.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/merge/structures/DisplayCoordinator.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/merge/structures/StructDisplayModel.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/merge/structures/StructureComponentLine.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/merge/structures/StructureDescriptionLine.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/merge/structures/StructureInfoLine.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/merge/structures/StructureMergeDialog.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/merge/structures/StructureNameLine.java create mode 100644 Ghidra/Features/Base/src/test/java/ghidra/app/merge/structures/CoordinatedStructureModelTest.java create mode 100644 Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/merge/StructureBuilder.java diff --git a/Ghidra/Features/Base/certification.manifest b/Ghidra/Features/Base/certification.manifest index 86eea1fbd4..b35d3593a3 100644 --- a/Ghidra/Features/Base/certification.manifest +++ b/Ghidra/Features/Base/certification.manifest @@ -351,6 +351,7 @@ src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.ht src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_window.html||GHIDRA||||END| src/main/help/help/topics/DataTypeManagerPlugin/images/CommitDialog.png||GHIDRA||||END| src/main/help/help/topics/DataTypeManagerPlugin/images/DataTypeManager.png||GHIDRA||||END| +src/main/help/help/topics/DataTypeManagerPlugin/images/DataTypeTreeWithAssociations.png||GHIDRA||||END| src/main/help/help/topics/DataTypeManagerPlugin/images/DisassociateDialog.png||GHIDRA||||END| src/main/help/help/topics/DataTypeManagerPlugin/images/EditPaths.png||GHIDRA||||END| src/main/help/help/topics/DataTypeManagerPlugin/images/FavoriteDts.png||GHIDRA||||END| @@ -361,6 +362,7 @@ src/main/help/help/topics/DataTypeManagerPlugin/images/MergeErrorDialog.png||GHI src/main/help/help/topics/DataTypeManagerPlugin/images/PreviewWindow.png||GHIDRA||||END| src/main/help/help/topics/DataTypeManagerPlugin/images/RevertDialog.png||GHIDRA||||END| src/main/help/help/topics/DataTypeManagerPlugin/images/SearchResults.png||GHIDRA||||END| +src/main/help/help/topics/DataTypeManagerPlugin/images/StructureMergeDialog.png||GHIDRA||||END| src/main/help/help/topics/DataTypeManagerPlugin/images/UpdateDialog.png||GHIDRA||||END| src/main/help/help/topics/DataTypeManagerPlugin/images/lockoverlay.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END| src/main/help/help/topics/DataTypePreviewPlugin/DataTypePreviewPlugin.html||GHIDRA||||END| diff --git a/Ghidra/Features/Base/data/base.icons.theme.properties b/Ghidra/Features/Base/data/base.icons.theme.properties index 98e7689a3a..729e6b709b 100644 --- a/Ghidra/Features/Base/data/base.icons.theme.properties +++ b/Ghidra/Features/Base/data/base.icons.theme.properties @@ -402,7 +402,7 @@ icon.base.mem.search.panel.scan = view_bottom.png icon.base.mem.search.panel.search = view_top_bottom.png icon.base.plugin.quickfix.done = icon.checkmark.green - +icon.base.merge.struct.apply = icon.checkmark.green[size(12,12)] [Dark Defaults] diff --git a/Ghidra/Features/Base/data/base.theme.properties b/Ghidra/Features/Base/data/base.theme.properties index f77102a815..f461cc6537 100644 --- a/Ghidra/Features/Base/data/base.theme.properties +++ b/Ghidra/Features/Base/data/base.theme.properties @@ -169,7 +169,7 @@ color.bg.plugin.overview.entropy.palette.base.high = color.palette.white color.bg.plugin.references.table.active.operand = color.palette.lightgray -color.bg.plugin.register.marker = color.palette.darkcyan +color.bg.plugin.register.marker = color.palette.darkcyan color.bg.plugin.windowlocation = color.palette.black color.bg.plugin.windowlocation.bounds.virtual = color.palette.red @@ -178,6 +178,8 @@ color.bg.plugin.windowlocation.screens = color.palette.orange color.bg.plugin.windowlocation.window.selected = color.palette.lime color.fg.plugin.windowlocation.window.text = color.palette.gray +color.bg.plugin.struct.merge.selection.non.focused = rgb(211, 211, 211) + font.print = SansSerif-PLAIN-10 font.splash.infopanel = SansSerif-BOLD-14 @@ -215,5 +217,6 @@ font.textarea.astextfield = [laf.font]TextField.font color.bg.undefined = #3A2A48 color.fg.analysis.options.prototype.selected = color.palette.crimson +color.bg.plugin.struct.merge.selection.non.focused = rgb(15, 42, 61) diff --git a/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm b/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm index 8872548c81..c0c7e426d1 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm @@ -1095,22 +1095,70 @@
-Some data types can be merged with others of the same type, provided there are no - conflicting entries in the two data types. Currently, - structures, unions and enums are supported for merging. If a conflict is detected, - an error dialog will be displayed showing the two data types and a message explaining - why the merge failed.
+Some data types can be merged with others of the same type.
+Currently, Ghidra supports + merging structures, unions, and enums. Unions and enums have limited support in that you + can only merge them if there are no conflicts and Ghidra can auto-merge them. For + structures, Ghidra will launch an interactive structure merger dialog that allows users + to pick and choose various elements from either structure.
+To Merge a data type, right-click on the type to be merged into and select the + Merge... action. This will show a + dialog that allows + you to choose the data type to merge with. +
+ +Merging Structures
+++When merging structures, an interactive dialog will be displayed showing the two + structures being merged along with a preview of the resulting merged structure. +
+ ++
++ +In the upper half of the dialog, the two structures being merged are displayed side by + side and aligned by offset. The lower section displays the resulting structure which changes + as the user selects different components from the two structures being merged. All three + structure views scroll together and selecting a line in any view, will also select + the corresponding line in the other views.
+In between the the display of the two input structures is a button panel that displays + buttons on any lines where there is a conflict and the user has a choice to select the + values from the left or right side structure.
+The displays of the left/right input structures will have optional values bolded or + faded, depending on if that value is currently chosen to be included in the resulting + merged structure.
+Selecting a button will cause that side's corresponding values to be applied to the + resulting structure and will cause any conflicting components from the other side to + be removed.
+Buttons associated with structure component lines can also be deselected, clearing + the corresponding component from the merged structure.
+The choices for the structure name and description always require one side or the + other to be selected, but for component choices, it is possible also deselect a button, + causing the resulting structure to not have a value from either side, instead reverting + to undefined bytes.
+The dialog has several features to make it easier to control from just the keyboard. + Using the tab and
+tab, the focus can be quickly moved between the left display, + the right display, the merged display, apply button and the cancel button. In addition, + you can quickly jump to the the left or right display by pressing the left or + right arrow keys respectively. Also, you can apply/unapply a left or right side item by + navigating to the item on the left or right side and pressing the [SPACE] key. Also, you can quickly give focus to the left or right display, by pressing the + [LEFT ARROW] or [RIGHT ARROW] keys respectively.
+When the resulting structure has been adjusted to the desired result, press the + Apply button to perform the merge.
+Merging Enums and Unions
+++Merging Enums and Unions is a simple pass/fail action. Generally, enums and unions + will merge without conflicts unless one or more elements have the same name for different + values/datatypes.
If the merge succeeds in producing a merged data type result, a confirmation dialog will be displayed showing the result and the two datatypes being merged. If the user confirms the merge, the original target data type will have its internals replaced with the merged data type and the other data type will have all its references replaced with the resulting datatype and then it will be deleted.
-To Merge a data type, right-click on the type to be merged into and select the - Merge... action. This will show a - dialog that allows - you to choose the data type to merge with. -
If the merge succeeds in producing a merged data type, the following confirmation dialog will be displayed before the changes are actually applied.
@@ -1123,7 +1171,6 @@ with the merge. If the user presses the apply button, the first data type will be updated to match the preview data type and the second data type will be deleted with all of its uses replaced with the updated first data type. -If the merge fails, the following error dialog is displayed showing a side-by-side view of the two data types that couldn't be merged, along with a description of the error @@ -1134,6 +1181,7 @@
hW7IQ;Pvum;)FXb<6=jge5?bx;Kt%|F}
z^S<7x+9s)|*(|BK_WWqGm1h>Fq7tH;D9X;>%sF*vlfAifK}W+)3;Esvq9`YKxip+n
zIvJ6c#?Hj_TF8EgS-bDO?%`BSi5RW_uES`Vry&TmxBMXiIq*gV3=O4-%kGa|`4W<#
z*a~BUj>V=eMmNPE98`1l$+}9o>ci-in@xOVY)pLRZF({xi*Y6zlU6BR1(e30xEkiW
zujZ5CmWw(QhFe1;MOvH763BQ+_W{EQp8G7|$&w3vQ77j?J%` ^z5sShB9iODtO+ijhw;aFpbHCm$$qw^H
zmPOEQ*d5KT*~Vv^6awOR&Wd`ngmRL&dnVA0_4KEo_UEHRXQV)G4ed@3&H&tkK<8|y
zN}Bq;B!}oPvOtZC4pz(8GC_Aikzrrf88u@3C-*7rL8@zlUJyFGMlk<3Pn`YBxtCMW
z*~Ia2y`_9i(Sc9xTS8EJWhw(T0?j0HKv7UDq$DIL;HE?tp+jn1QyF4`{~}mFubwTT
zB}m^m#qx>Fp(?fwShV&0kJJ*kJiw9c8EI)%jmlh!Aq7iutvR3t;7@vKKSO%}wfFyq
z+F~*^Gf!U{w`S&bqp#0pxH8+?9)h?VU7AbkrmamO2xRP6uU>szWQJMfeF-T6JBqFJ
zb_d5bo+J+LaI|_L49v}$0U(FQa_S+9&w()Ti|XL5pGVFJ=yF2^W`X(-hcS*w&?D16
z(ifZn!W{9jxw*MWFE4oNdU2%@Adg~V37>WHx%0Gu=RJ@3k3)DZVzaitoxky;A&fS_
zTGVG{|KxBD2@=2f6+`f->(|qPKMwT`#+26d?7%=k{+*jVh6CFjI1BRn)R5M3HG}4B
zkS+E}M!!9ohgUgFswyr^r$~C2$cnooX8rJ88~@^Y29;iD5lO(kze)aYIY^+o`V!cK
zZ`JrDL=Jw|DMfkq1TYx_>9g6KUHruz|GpSU!Uc76{(!-M{#&l-O|kH#`6r{fh){c8
z!4!Y=2yGZQRHlID3_NqqU#duAS0U@me_Ztz6z(%~c}UEwq}*1|L2hO7F4OAjn*GfG
z5_=0FuQ)!L-#1rCnpWMK&a?@a+HyCub7=y#N7WhHF|?B;<$+EuZ9
z`S$BH0zq$y=%EI4pWDd$b_xm#KzyepCNK9ZZA+jLga+Zh;0Xjih~g2rM+5u5LN`L6
zbulN06FTta_Qi`AMSGQ(TMVC(+xLFf%JSY_jsEZfB~-Mc6T2aYX=+je!YwtIUZI@L
zMX&~)vo(}cK~y(2u@9A$E(0%&;N#=_xJXsbr{gg+mY1YYK~Mh(T&C>*j31f)?~yNZ
zLGS+c*E_GBWg7!4o!P7E!^7wzjwNgsY5NCWSuT8>IDd9;3@Ash6vw=}DVPFv7%a@N
z2gb@FVei=Ak!Ocn?48_}z=vQwAHRuiw-%FDzzgLs$bVUp&gytBDVqKtbHSS$&jzKB
zmp;CBC4c_^9K#(Q4W0h^{WbQ#BiYb%#$0_g$?ioR$YBH=o>t|1*lmv)RX9E9uSS8o
z6}H6QV5rz8N>-e{FA?=S!pSr@H>
`J1K-@+OK2YV5XsG{aI`FAl-nagF&DQ@|*C@L|bHd$VFc`2U1{LWXJZRE|q*}4K}
z=j@Jnk-WK9qN%;9Ic(CZC0dx%y92K|tEMW!ZpeSuLh+)?+-q~mR?U*MuEY`Nz(Ngp
zv3EUAXX+nC|Kg7QNiv_?qlkqrii32imE-!E9(a8~W`x4ow`6
L=V~OlF9|mRj)DBHTk_A;1=0#1{Z;ee
z#PcJ>ujb-aROhQle9mcK8$;oOlGpAAkxHU+$)%7#&T)AeNS7%ThWq3uyr5@deiwtw
zx{AP3qQHlLd@vvZ5U316iUmGE+LZsa+y9rv%Fp)XD_pV{Mml1;%!(uzbX7a6ZAESC
zuny|qt3V0K@j@d8D@D9ndyu2lai~?`P-a8gsjfU)>wLz5`^GsZ#93f?dL;
z@S1a5p!TRTt|ajdLUt|W(6Tms!&~{J52!TS2^hqZqNuZh9Im%@29J}X1ZZ~|k!cI_
zemPn81aAEq`nAbRA{!}7Z+Y2!#TI;%yOgkXjEJs>%B1O_3#ap|)2r6U%USR+g+A)H
z&*%zZkQks_aMtfFKx>3Y)ZDJJItoAhv}&AiYuB7`#TO{)t*p_T!vQ9UTtE|#Z{pOk
z7@<}QG|7CX;sY8LAft-9z}2!l5v+LEA8D*DR-Kpg-j#P}T3vR@Ak5G~@7?nR0>j35
z`L5sMvA)lBi$U8{Q>0sSF2-D%