On this article, I will talk about how I’ve refactored some parts of the previous module (hexdump) to make it reusable for the disasembly. Both module have a lot of similarities: infinite scrolling, contextual menu, flex container, etc.
OO, inheritance, refactoring…
This way, I can reuse some similar code between modules. Also, this way allows to redefine some methods by calling them with
This way, inheritance is usable easily and, with some refactoring on flex container and the way infinite scrolling is implemented, I can reuse a lot of code without duplication.
At beginning, the whole behavior of the hexdump was tightly coupled. Not a good idea to keep it as is, but, good enough in first time to elaborate the module and refactor then.
Best example here is the infinite module. It’s the module that handle, at the UI level, the event to be triggered when we are close to reach the end (or beginning) of the current view. That module has to be plugged to a specific container (a block with a defined height). In our case, it works well with the flex container. I’ve separated them by simplicity: one handle the drawing of the UI, the other the behavior, we can use them individually: better reuse.
Also, the flex container has been refined to be considered as a widget and be able to fit the new needs. Currently, it implement a loading dialog to make user wait for action to end before reaching the interface. I want it to be more powerful by adding a way to prompt more powerfully the user. Currently, we use the native
prompt() which is ok for now, but this new component would allows us to present elaborated choices, steps to go, etc.
How disassembly panel works?
The needs behind this module were pretty similar to the hexdump panel: infinite scrolling, contextual menu, background processing, etc. One big change: the data comes already HTML-ready. No JSON or chain to parse, everything is ready to be integrated to the browser. Also, data needs to be read in specific portion, depending of internal analysis (analysis method is made by the user).
So, first step here, before starting anything: crunching some data about the functions and flags. I need to know were they are and what they cover (length). Process is pretty simple:
- fetch all flags and functions
- delete all chunks too big to be shown
- if there is duplicated offsets, keep the biggest
Send this list to the UI (this part use web workers for fluidity). Every time the user will ask a new analysis, we will reprocess this part to improve the ref-lines drawing.
Back to the UI, we then ask chunks with an intermediate: the disasm navigator. The exception is that we redraw all the line every time we scroll. Providing the UI with chunks can provide rather different results with a relative close offset (depending of the number of flags/functions referenced at this place).
The navigator ensure cache for performances and the choice of the chunk to fill the current window with proper content. The fact we redraw the whole container isn’t a problem. The HTML is processed by r2, it’s quick, and the content suffers few manipulations before insertion into the DOM. Like for the hexdump, this module use web workers to exchange with r2 and apply the few processing it needs.
Infinite scrolling with randomly sized chunks
One of the challenge with this module was to tweak the infinite scrolling to set the position after scroll at the good position. As I said before, the content is redrawn entierly every time we trigger the scroll event and the user should be able to follow his previous offset without scrolling.
There is enough things into the current browser API to know which element is visible inside a element with a scrollbar but here, we works with blocks of pre-processed HTML. And more than that, every lines doesn’t have an offset:
So, I’ve decided to make somehting simple to guess the most probable offset and repositionate the next chunks at the optimal place. This guess is made simple: calculate the portion visible of the block, getting the probable offset. Then, let the UI draw the next chunks, getting the chunk on which there is my guessed offset and, placing, approximately (with a margin) how to set my scrollTop property to find my last offset as it should be.
A new component compared to the previous panel is the nav bar, or the history. It’s a module that allows the user to navigate through the different offset he has been seeking like the navigation button of the browser.
Next step would be to globalize this history for all modules. Currently, offset isn’t systematically reported to each module in real time. We refresh with the current offset when the panel has to be (re)drawn. Would be great to define some basic component with a listener/observer logic to help organize the UI.