1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
use clap::{Parser, Subcommand, ValueEnum};
use std::path::PathBuf;
#[derive(Parser)]
#[command(name = "layout-audit")]
#[command(
author,
version,
about = "Analyze binary memory layouts to detect padding inefficiencies"
)]
#[command(
long_about = "layout-audit parses DWARF debugging information to visualize the physical \
layout of data structures, detect padding holes, and analyze cache line efficiency.\n\n\
Example:\n layout-audit inspect ./target/debug/myapp --filter MyStruct"
)]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
}
#[derive(Subcommand)]
pub enum Commands {
/// Analyze and display struct layouts from a binary
Inspect {
/// Path to the binary file to analyze
#[arg(value_name = "BINARY")]
binary: PathBuf,
/// Filter structs by name (substring match)
#[arg(short, long)]
filter: Option<String>,
/// Output format (table, json, sarif)
#[arg(short, long, value_enum, default_value = "table")]
output: OutputFormat,
/// Sort structs by field
#[arg(short, long, value_enum, default_value = "name")]
sort_by: SortField,
/// Show only the top N structs (by sort order)
#[arg(short = 'n', long)]
top: Option<usize>,
/// Show only structs with at least N bytes of padding
#[arg(long)]
min_padding: Option<u64>,
/// Disable colored output
#[arg(long)]
no_color: bool,
/// Cache line size in bytes (must be > 0)
#[arg(long, default_value = "64", value_parser = clap::value_parser!(u32).range(1..))]
cache_line: u32,
/// Pretty-print JSON output
#[arg(long)]
pretty: bool,
/// Warn about potential false sharing between atomic members on the same cache line
#[arg(long)]
warn_false_sharing: bool,
/// Include Go runtime internal types (filtered by default)
#[arg(long)]
include_go_runtime: bool,
},
/// Compare struct layouts between two binaries
Diff {
/// Path to the old (baseline) binary
#[arg(value_name = "OLD")]
old: PathBuf,
/// Path to the new binary
#[arg(value_name = "NEW")]
new: PathBuf,
/// Filter structs by name (substring match)
#[arg(short, long)]
filter: Option<String>,
/// Output format (table, json, sarif)
#[arg(short, long, value_enum, default_value = "table")]
output: OutputFormat,
/// Cache line size in bytes (must be > 0)
#[arg(long, default_value = "64", value_parser = clap::value_parser!(u32).range(1..))]
cache_line: u32,
/// Exit with error code 1 if any regressions found (size or padding increased)
#[arg(long)]
fail_on_regression: bool,
/// Include Go runtime internal types (filtered by default)
#[arg(long)]
include_go_runtime: bool,
},
/// Check struct layouts against budget constraints
Check {
/// Path to the binary file to analyze
#[arg(value_name = "BINARY")]
binary: PathBuf,
/// Path to config file (.layout-audit.yaml)
#[arg(short, long, default_value = ".layout-audit.yaml")]
config: PathBuf,
/// Output format (table, json, sarif)
#[arg(short, long, value_enum, default_value = "table")]
output: OutputFormat,
/// Cache line size in bytes (must be > 0)
#[arg(long, default_value = "64", value_parser = clap::value_parser!(u32).range(1..))]
cache_line: u32,
/// Include Go runtime internal types (filtered by default)
#[arg(long)]
include_go_runtime: bool,
},
/// Suggest optimal field ordering to minimize padding
Suggest {
/// Path to the binary file to analyze
#[arg(value_name = "BINARY")]
binary: PathBuf,
/// Filter structs by name (substring match)
#[arg(short, long)]
filter: Option<String>,
/// Output format (table, json, sarif)
#[arg(short, long, value_enum, default_value = "table")]
output: OutputFormat,
/// Show only structs with at least N bytes of potential savings
#[arg(long)]
min_savings: Option<u64>,
/// Cache line size in bytes (must be > 0)
#[arg(long, default_value = "64", value_parser = clap::value_parser!(u32).range(1..))]
cache_line: u32,
/// Pretty-print JSON output
#[arg(long)]
pretty: bool,
/// Maximum alignment to assume for types (typically 8 on 64-bit)
#[arg(long, default_value = "8", value_parser = clap::value_parser!(u64).range(1..))]
max_align: u64,
/// Sort suggestions by savings amount (largest first)
#[arg(long)]
sort_by_savings: bool,
/// Disable colored output
#[arg(long)]
no_color: bool,
/// Include Go runtime internal types (filtered by default)
#[arg(long)]
include_go_runtime: bool,
},
}
#[derive(Copy, Clone, PartialEq, Eq, ValueEnum)]
pub enum OutputFormat {
Table,
Json,
Sarif,
}
#[derive(Copy, Clone, PartialEq, Eq, ValueEnum)]
pub enum SortField {
/// Sort by struct name (alphabetical)
Name,
/// Sort by total size (largest first)
Size,
/// Sort by padding bytes (most padding first)
Padding,
/// Sort by padding percentage (worst efficiency first)
PaddingPct,
}