feat: Add string-level highlighting in hex view and sync highlight to matching section string entries#8
feat: Add string-level highlighting in hex view and sync highlight to matching section string entries#8harkerhand wants to merge 2 commits intorbakbashev:masterfrom
Conversation
…dling style: highlight strtab_str on hover
…ices; enhance string table range handling js: add highlighting functionality for strtab sections report_gen: modify string table generation to include section and string indices; escape HTML characters style: add styles for strtab entries and active highlighting
There was a problem hiding this comment.
Pull request overview
This PR adds finer-grained highlighting for ELF string table content by introducing per-string ranges in the hex view and synchronizing hover highlighting to corresponding string entries in the section details panel.
Changes:
- Add a new
RangeType::StrtabString(section_idx, str_idx)and generate per-string ranges forSHT_STRTABsections. - Emit per-string
<span>entries in the STRTAB section detail table (with HTML escaping) and link them to hex-view ranges via sharedstrtab_ref{section}_{str}classes. - Add JS + CSS to sync hover state from hex-view string spans to the matching STRTAB entries.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| src/style.css | Adds styles for STRTAB string hover and active entry highlighting. |
| src/report_gen.rs | Adds HTML escaping and emits per-string STRTAB entries with reference classes; wires in new sync-highlighting JS. |
| src/js/highlight.js | Adds document-level hover handler to activate matching STRTAB entries based on hex-view hover target. |
| src/elf/parser.rs | Introduces StrtabString range type and populates per-string ranges for SHT_STRTAB sections. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if *c == 0 { | ||
| let end = if curr_start == 0 { 0 } else { i - 1 }; | ||
|
|
||
| let maybe = std::str::from_utf8(§ion[curr_start..=end]); | ||
|
|
There was a problem hiding this comment.
generate_strtab_data can panic on valid string tables containing consecutive \0 bytes (empty strings/padding). When i == curr_start and curr_start != 0, end becomes i - 1, making the inclusive slice section[curr_start..=end] invalid (start > end). Consider skipping empty strings before slicing, and avoid the special-casing of curr_start == 0 so the first (potentially non-empty) string is handled correctly too.
| w!( | ||
| o, | ||
| 9, | ||
| "<span class='strtab_entry strtab_ref{}_{}'>{}</span>", | ||
| section_idx, | ||
| str_idx, | ||
| escape_html_str(string) | ||
| ); | ||
| str_idx += 1; |
There was a problem hiding this comment.
add_strtab_ranges() (parser side) adds a final string range when the section doesn't end with \0, but this renderer only emits entries when it hits a NUL terminator. That can leave highlighted .strtab_str ranges with no matching .strtab_entry (sync highlight no-ops). Consider emitting a final entry after the loop when curr_start < section.len() to match the range-generation behavior.
| if let Ok(string) = maybe { | ||
| if section[curr_start] != 0 { | ||
| w!(o, 9, "{}", string); | ||
| w!( | ||
| o, | ||
| 9, | ||
| "<span class='strtab_entry strtab_ref{}_{}'>{}</span>", | ||
| section_idx, | ||
| str_idx, | ||
| escape_html_str(string) | ||
| ); | ||
| str_idx += 1; | ||
| } | ||
| } |
There was a problem hiding this comment.
Sync-highlighting is keyed off str_idx, but this code only emits .strtab_entry elements for strings where std::str::from_utf8(...) succeeds. add_strtab_ranges() will still create .strtab_str spans for non-UTF8 byte sequences, so hovering those bytes won't highlight anything on the right. Consider rendering non-UTF8 strings using a lossless/escaped representation (e.g., from_utf8_lossy or hex-escaped bytes) so every highlighted range has a corresponding entry.
| fn add_strtab_ranges(&mut self) { | ||
| let mut str_ranges: Vec<(usize, usize, u16, u32)> = Vec::new(); | ||
|
|
There was a problem hiding this comment.
add_strtab_ranges builds a Vec of all string ranges (str_ranges) and then iterates again to add them to self.ranges. This can double memory usage for large string tables. You can usually avoid the temporary vector by borrowing disjoint fields (let (ranges, shdrs, contents) = (&mut self.ranges, &self.shdrs, self.contents);) and calling ranges.add_range(...) directly while iterating.
| document.addEventListener("mouseover", function(event) { | ||
| let refClass = getRefClass(event.target); | ||
|
|
||
| clearActiveEntries(); | ||
|
|
||
| if (refClass === null) { | ||
| return; | ||
| } | ||
|
|
||
| let entries = document.querySelectorAll(".strtab_entry." + refClass); | ||
|
|
||
| for (let entry of entries) { | ||
| entry.classList.add("strtab_entry_active"); | ||
| activeEntries.push(entry); | ||
| } | ||
| }, false); |
There was a problem hiding this comment.
This adds a document-level mouseover handler that runs on every mouseover anywhere in the page, clearing/re-adding classes and doing a querySelectorAll each time. On large dumps this can become a noticeable hotspot. Consider either (1) using event delegation but tracking the last refClass and returning early when it hasn't changed, and/or (2) attaching mouseenter/mouseleave listeners only to .strtab_str elements and pre-indexing .strtab_entry nodes by refClass.
The current implementation already has section-level highlighting, but it lacks finer-grained visualization for string-dense areas (such as string tables). I have provided secondary string highlighting and added the linkage between the left-side Hex highlighting and the section detail strings on the right.
An example is shown in the figure below (blue style) :