Skip to content

Commit fd27f4d

Browse files
authored
cli diff: Resolve object and project if not specified (#44)
* cli diff: Resolve object and project if not specified * Make `symbol` positional * Short circuit ambiguous matches * Tighten argument matching * Speed up function lookup
1 parent 5cfd04f commit fd27f4d

File tree

2 files changed

+67
-14
lines changed

2 files changed

+67
-14
lines changed

objdiff-cli/src/cmd/diff.rs

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crossterm::{
2020
};
2121
use event::KeyModifiers;
2222
use objdiff_core::{
23-
config::ProjectConfig,
23+
config::{ProjectConfig, ProjectObject},
2424
diff,
2525
diff::display::{display_diff, DiffText, HighlightKind},
2626
obj,
@@ -45,33 +45,75 @@ pub struct Args {
4545
#[argp(option, short = 'u')]
4646
/// Unit name within project
4747
unit: Option<String>,
48-
#[argp(option, short = 's')]
48+
#[argp(positional)]
4949
/// Function symbol to diff
5050
symbol: String,
5151
}
5252

5353
pub fn run(args: Args) -> Result<()> {
5454
let (target_path, base_path, project_config) =
5555
match (&args.target, &args.base, &args.project, &args.unit) {
56-
(Some(t), Some(b), _, _) => (Some(t.clone()), Some(b.clone()), None),
57-
(_, _, Some(p), Some(u)) => {
56+
(Some(t), Some(b), None, None) => (Some(t.clone()), Some(b.clone()), None),
57+
(None, None, p, u) => {
58+
let project = match p {
59+
Some(project) => project.clone(),
60+
_ => std::env::current_dir().context("Failed to get the current directory")?,
61+
};
5862
let Some((project_config, project_config_info)) =
59-
objdiff_core::config::try_project_config(p)
63+
objdiff_core::config::try_project_config(&project)
6064
else {
61-
bail!("Project config not found in {}", p.display())
65+
bail!("Project config not found in {}", &project.display())
6266
};
6367
let mut project_config = project_config.with_context(|| {
6468
format!("Reading project config {}", project_config_info.path.display())
6569
})?;
66-
let Some(object) = project_config.objects.iter_mut().find(|obj| obj.name() == u)
67-
else {
68-
bail!("Unit not found: {}", u)
70+
let object = {
71+
let resolve_paths = |o: &mut ProjectObject| {
72+
o.resolve_paths(
73+
&project,
74+
project_config.target_dir.as_deref(),
75+
project_config.base_dir.as_deref(),
76+
)
77+
};
78+
if let Some(u) = u {
79+
let Some(object) =
80+
project_config.objects.iter_mut().find(|obj| obj.name() == u)
81+
else {
82+
bail!("Unit not found: {}", u)
83+
};
84+
resolve_paths(object);
85+
object
86+
} else {
87+
let mut idx = None;
88+
let mut count = 0usize;
89+
for (i, obj) in project_config.objects.iter_mut().enumerate() {
90+
resolve_paths(obj);
91+
92+
if obj
93+
.target_path
94+
.as_deref()
95+
.map(|o| obj::elf::has_function(o, &args.symbol))
96+
.transpose()?
97+
.unwrap_or_default()
98+
{
99+
idx = Some(i);
100+
count += 1;
101+
if count > 1 {
102+
break;
103+
}
104+
}
105+
}
106+
match (count, idx) {
107+
(0, None) => bail!("Symbol not found: {}", &args.symbol),
108+
(1, Some(i)) => &mut project_config.objects[i],
109+
(2.., Some(_)) => bail!(
110+
"Multiple instances of {} were found, try specifying a unit",
111+
&args.symbol
112+
),
113+
_ => unreachable!(),
114+
}
115+
}
69116
};
70-
object.resolve_paths(
71-
p,
72-
project_config.target_dir.as_deref(),
73-
project_config.base_dir.as_deref(),
74-
);
75117
let target_path = object.target_path.clone();
76118
let base_path = object.base_path.clone();
77119
(target_path, base_path, Some(project_config))

objdiff-core/src/obj/elf.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,17 @@ pub fn read(obj_path: &Path) -> Result<ObjInfo> {
394394
Ok(result)
395395
}
396396

397+
pub fn has_function(obj_path: &Path, symbol_name: &str) -> Result<bool> {
398+
let data = {
399+
let file = fs::File::open(obj_path)?;
400+
unsafe { memmap2::Mmap::map(&file) }?
401+
};
402+
Ok(File::parse(&*data)?
403+
.symbol_by_name(symbol_name)
404+
.filter(|o| o.kind() == SymbolKind::Text)
405+
.is_some())
406+
}
407+
397408
fn split_meta(obj_file: &File<'_>) -> Result<Option<SplitMeta>> {
398409
Ok(if let Some(section) = obj_file.section_by_name(SPLITMETA_SECTION) {
399410
if section.size() != 0 {

0 commit comments

Comments
 (0)