Skip to content

Commit c7c02ae

Browse files
committed
progress
1 parent 85f4374 commit c7c02ae

File tree

4 files changed

+152
-26
lines changed

4 files changed

+152
-26
lines changed

src/launchpad/parsers/apple/macho_parser.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import lief
1212
import sentry_sdk
1313

14-
from launchpad.size.models.apple import DyldInfo
14+
from launchpad.size.models.apple import CodeSignatureInfo, DyldInfo, LinkEditInfo
1515

1616
from ...utils.logging import get_logger
1717
from .binary_utils import parse_null_terminated_strings
@@ -308,3 +308,48 @@ def extract_dyld_info(self) -> DyldInfo:
308308
chained_fixups_size=(dyld_chained_fixups.data_size if dyld_chained_fixups else 0),
309309
export_trie_size=dyld_exports_trie.data_size if dyld_exports_trie else 0,
310310
)
311+
312+
@sentry_sdk.trace
313+
def extract_code_signature_info(self) -> CodeSignatureInfo | None:
314+
"""Extract code signature information from LC_CODE_SIGNATURE load command."""
315+
if not self.binary.has_code_signature:
316+
return None
317+
318+
cs = self.binary.code_signature
319+
return CodeSignatureInfo(
320+
size=cs.data_size,
321+
offset=cs.data_offset,
322+
)
323+
324+
@sentry_sdk.trace
325+
def extract_linkedit_info(self) -> LinkEditInfo:
326+
"""Extract __LINKEDIT segment component sizes from load commands."""
327+
symbol_table_size = 0
328+
string_table_size = 0
329+
function_starts_size = 0
330+
segment_size = 0
331+
332+
is_64bit = self.binary.header.magic in [
333+
lief.MachO.MACHO_TYPES.MAGIC_64,
334+
lief.MachO.MACHO_TYPES.CIGAM_64,
335+
]
336+
entry_size = 16 if is_64bit else 12
337+
338+
for cmd in self.binary.commands:
339+
if isinstance(cmd, lief.MachO.SymbolCommand):
340+
symbol_table_size = cmd.numberof_symbols * entry_size
341+
string_table_size = cmd.strings_size
342+
elif isinstance(cmd, lief.MachO.FunctionStarts):
343+
function_starts_size = cmd.data_size
344+
345+
for segment in self.binary.segments:
346+
if segment.name == "__LINKEDIT":
347+
segment_size = segment.file_size
348+
break
349+
350+
return LinkEditInfo(
351+
symbol_table_size=symbol_table_size,
352+
string_table_size=string_table_size,
353+
function_starts_size=function_starts_size,
354+
segment_size=segment_size,
355+
)

src/launchpad/size/analyzers/apple.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,8 @@ def _analyze_binary(
440440
segments = self._extract_segments_info(parser.binary)
441441
load_commands = self._extract_load_commands_info(parser.binary)
442442
dyld_info = parser.extract_dyld_info()
443+
code_signature_info = parser.extract_code_signature_info()
444+
linkedit_info = parser.extract_linkedit_info()
443445

444446
symbol_info = None
445447
dwarf_relocations = None
@@ -499,6 +501,8 @@ def _analyze_binary(
499501
dyld_info=dyld_info,
500502
dwarf_relocations=dwarf_relocations,
501503
strippable_symbols_size=strippable_symbols_size,
504+
code_signature_info=code_signature_info,
505+
linkedit_info=linkedit_info,
502506
)
503507

504508
@sentry_sdk.trace

src/launchpad/size/models/apple.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,24 @@ class DyldInfo:
134134
export_trie_size: int = 0
135135

136136

137+
@dataclass
138+
class CodeSignatureInfo:
139+
"""Code signature information extracted from LC_CODE_SIGNATURE load command."""
140+
141+
size: int = 0
142+
offset: int = 0
143+
144+
145+
@dataclass
146+
class LinkEditInfo:
147+
"""Link edit segment components extracted from various load commands in __LINKEDIT."""
148+
149+
symbol_table_size: int = 0
150+
string_table_size: int = 0
151+
function_starts_size: int = 0
152+
segment_size: int = 0
153+
154+
137155
@dataclass
138156
class MachOBinaryAnalysis:
139157
"""Mach-O binary analysis results."""
@@ -153,6 +171,8 @@ class MachOBinaryAnalysis:
153171
dyld_info: DyldInfo | None = None
154172
dwarf_relocations: DwarfRelocationsData | None = None
155173
strippable_symbols_size: int = 0
174+
code_signature_info: CodeSignatureInfo | None = None
175+
linkedit_info: LinkEditInfo | None = None
156176

157177

158178
@dataclass

src/launchpad/size/treemap/macho_element_builder.py

Lines changed: 82 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -435,11 +435,11 @@ def _add_segments(
435435
)
436436
)
437437

438-
dyld_children_size = 0
438+
linkedit_children_size = 0
439439
if segment_name == "__LINKEDIT":
440-
dyld_children = self._build_dyld_load_command_children(binary_analysis)
441-
segment_children.extend(dyld_children)
442-
dyld_children_size = sum(c.size for c in dyld_children)
440+
linkedit_children = self._build_linkedit_children(binary_analysis)
441+
segment_children.extend(linkedit_children)
442+
linkedit_children_size = sum(c.size for c in linkedit_children)
443443

444444
displayed_section_size = sum(c.size for c in segment_children)
445445

@@ -448,7 +448,7 @@ def _add_segments(
448448
seg_total_size = segment.size
449449

450450
total_section_declared = sum(s.size for s in segment.sections) if segment.sections else 0
451-
segment_overhead = seg_total_size - total_section_declared - dyld_children_size
451+
segment_overhead = seg_total_size - total_section_declared - linkedit_children_size
452452
actual_segment_size = displayed_section_size + max(0, segment_overhead)
453453

454454
if actual_segment_size > 0:
@@ -503,37 +503,94 @@ def _build_metadata_components(self, binary_analysis: MachOBinaryAnalysis) -> Li
503503

504504
return metadata_children
505505

506-
def _build_dyld_load_command_children(self, binary_analysis: MachOBinaryAnalysis) -> List[TreemapElement]:
507-
dyld_children: List[TreemapElement] = []
506+
def _build_linkedit_children(self, binary_analysis: MachOBinaryAnalysis) -> List[TreemapElement]:
507+
"""Build child elements for the __LINKEDIT segment.
508+
509+
Includes symbol table, string table, function starts, DYLD info, and code signature.
510+
"""
511+
linkedit_children: List[TreemapElement] = []
512+
513+
# Add link edit components (symbol table, string table, function starts)
514+
le = binary_analysis.linkedit_info
515+
if le is not None:
516+
if le.string_table_size > 0:
517+
linkedit_children.append(
518+
TreemapElement(
519+
name="String Table",
520+
size=le.string_table_size,
521+
type=TreemapType.EXECUTABLES,
522+
path=None,
523+
is_dir=False,
524+
children=[],
525+
)
526+
)
527+
528+
if le.symbol_table_size > 0:
529+
linkedit_children.append(
530+
TreemapElement(
531+
name="Symbol Table",
532+
size=le.symbol_table_size,
533+
type=TreemapType.EXECUTABLES,
534+
path=None,
535+
is_dir=False,
536+
children=[],
537+
)
538+
)
539+
540+
if le.function_starts_size > 0:
541+
linkedit_children.append(
542+
TreemapElement(
543+
name="Function Starts",
544+
size=le.function_starts_size,
545+
type=TreemapType.EXECUTABLES,
546+
path=None,
547+
is_dir=False,
548+
children=[],
549+
)
550+
)
551+
552+
# Add DYLD info children
508553
di = binary_analysis.dyld_info
509-
if di is None:
510-
return dyld_children
554+
if di is not None:
555+
if di.chained_fixups_size > 0:
556+
linkedit_children.append(
557+
TreemapElement(
558+
name="Chained Fixups",
559+
size=di.chained_fixups_size,
560+
type=TreemapType.DYLD,
561+
path=None,
562+
is_dir=False,
563+
children=[],
564+
)
565+
)
511566

512-
if di.chained_fixups_size > 0:
513-
dyld_children.append(
514-
TreemapElement(
515-
name="Chained Fixups",
516-
size=di.chained_fixups_size,
517-
type=TreemapType.DYLD,
518-
path=None,
519-
is_dir=False,
520-
children=[],
567+
if di.export_trie_size > 0:
568+
linkedit_children.append(
569+
TreemapElement(
570+
name="Export Trie",
571+
size=di.export_trie_size,
572+
type=TreemapType.DYLD,
573+
path=None,
574+
is_dir=False,
575+
children=[],
576+
)
521577
)
522-
)
523578

524-
if di.export_trie_size > 0:
525-
dyld_children.append(
579+
# Add code signature
580+
cs = binary_analysis.code_signature_info
581+
if cs is not None and cs.size > 0:
582+
linkedit_children.append(
526583
TreemapElement(
527-
name="Export Trie",
528-
size=di.export_trie_size,
529-
type=TreemapType.DYLD,
584+
name="Code Signature",
585+
size=cs.size,
586+
type=TreemapType.CODE_SIGNATURE,
530587
path=None,
531588
is_dir=False,
532589
children=[],
533590
)
534591
)
535592

536-
return dyld_children
593+
return linkedit_children
537594

538595
def _add_unmapped_region(self, binary_analysis: MachOBinaryAnalysis, binary_children: List[TreemapElement]) -> None:
539596
total_accounted = sum(c.size for c in binary_children)

0 commit comments

Comments
 (0)