pub struct TypesMut<'db> { /* private fields */ }Expand description
A write cursor over the database’s local type library, from Database::types_mut.
Holds the database exclusively. Exposes define for whole declarations and
edit for member surgery on an existing named type.
Implementations§
Source§impl TypesMut<'_>
impl TypesMut<'_>
Sourcepub fn define(&mut self, decl: impl AsRef<str>) -> Result<()>
pub fn define(&mut self, decl: impl AsRef<str>) -> Result<()>
Parse the C declaration(s) in decl into the database’s local type library.
A struct, union, enum, or typedef declaration becomes a named type that later
set_type calls can reference by name, and that
named_types then enumerates. Redeclarations are tolerated.
decl may hold several declarations. It is not atomic: on an error, declarations that
parsed before the failure are already defined.
db.types_mut().define("struct Point { int x; int y; };")?;
assert!(db.named_types().any(|t| t.name() == "Point"));§Errors
Error::TypeDefineFailed if IDA rejects any declaration (with its own diagnostics), or
Error::InteriorNul if decl contains a NUL byte.
Examples found in repository?
158fn defining_types(idb: &mut Database) -> Result<(), Error> {
159 println!("\n== types_mut: define ==");
160
161 idb.types_mut()
162 .define("struct edit_demo_t { int id; char *name; };")?;
163 let present = idb.named_types().any(|t| t.name() == "edit_demo_t");
164 println!(" defined edit_demo_t, present in named types: {present}");
165
166 // A declaration referencing the just-defined type resolves against the local til.
167 match idb
168 .types_mut()
169 .define("typedef struct edit_demo_t edit_demo_alias;")
170 {
171 Ok(()) => println!(" typedef alias to it: ok"),
172 Err(e) => println!(" typedef alias: {e}"),
173 }
174
175 // A malformed declaration is a typed error carrying IDA's own reason.
176 match idb.types_mut().define("struct broken { not valid") {
177 Err(Error::TypeDefineFailed { reason, .. }) => {
178 println!(" malformed define -> TypeDefineFailed: {reason}");
179 }
180 other => println!(" malformed define -> unexpected {other:?}"),
181 }
182 Ok(())
183}
184
185/// Member surgery on defined types: append/retype/rename struct fields through the `member(..)`
186/// sub-cursor (with the structured rejection when a rename collides), then add and revalue enum
187/// constants through `constant(..)`. Each edit auto-saves to the local til; nothing persists past
188/// `save = false`.
189fn editing_members(idb: &mut Database) -> Result<(), Error> {
190 use idakit::types::expr;
191
192 println!("\n== types_mut: edit members ==");
193
194 idb.types_mut()
195 .define("struct edit_member_demo { int a; int b; };")?;
196
197 idb.types_mut()
198 .edit("edit_member_demo")
199 .add_member("c", expr::int32())?;
200 idb.types_mut()
201 .edit("edit_member_demo")
202 .member("a")
203 .set_type(expr::char_())?;
204 idb.types_mut()
205 .edit("edit_member_demo")
206 .member("b")
207 .rename("beta")?;
208
209 let names: Vec<String> = idb
210 .type_named("edit_member_demo")?
211 .members()
212 .unwrap_or_default()
213 .iter()
214 .map(|m| m.name.clone())
215 .collect();
216 println!(" after add + retype + rename, members: {names:?}");
217
218 // Renaming onto an existing name surfaces the structured tinfo_code.
219 match idb
220 .types_mut()
221 .edit("edit_member_demo")
222 .member("c")
223 .rename("a")
224 {
225 Err(Error::TypeWrite {
226 source: TypeWriteError::Rejected { code, .. },
227 }) => println!(" duplicate rename -> Rejected({code})"),
228 other => println!(" duplicate rename -> unexpected {other:?}"),
229 }
230
231 // Enum constants use the same cursor: add, revalue, rename.
232 idb.types_mut()
233 .define("enum edit_enum_demo { DEMO_A = 1, DEMO_B = 2 };")?;
234 idb.types_mut()
235 .edit("edit_enum_demo")
236 .add_constant("DEMO_C", 3)?;
237 idb.types_mut()
238 .edit("edit_enum_demo")
239 .constant("DEMO_A")
240 .set_value(10)?;
241 let constants: Vec<(String, u64)> = match idb.type_named("edit_enum_demo")?.shape() {
242 TypeShape::Enum { members, .. } => {
243 members.iter().map(|m| (m.name.clone(), m.value)).collect()
244 }
245 _ => Vec::new(),
246 };
247 println!(" after add + revalue, constants: {constants:?}");
248 Ok(())
249}Sourcepub fn delete(&mut self, name: impl AsRef<str>) -> Result<()>
pub fn delete(&mut self, name: impl AsRef<str>) -> Result<()>
Delete the named type name from the database’s local type library.
The til-level inverse of define: removes a struct, union, enum, or
typedef entry outright. Not idempotent: deleting a name that does not exist is
TypeWriteError::NoType, the same treatment MemberEdit::delete gives an
unresolved member.
db.types_mut().define("struct Scratch { int x; };")?;
db.types_mut().delete("Scratch")?;
assert!(!db.named_types().any(|t| t.name() == "Scratch"));§Errors
TypeWriteError::NoType if no type named name exists, TypeWriteError::Rejected
if the kernel refuses the deletion, or Error::InteriorNul if name contains a NUL
byte.
Sourcepub fn rename(
&mut self,
name: impl AsRef<str>,
new_name: impl AsRef<str>,
) -> Result<()>
pub fn rename( &mut self, name: impl AsRef<str>, new_name: impl AsRef<str>, ) -> Result<()>
Rename the named type name to new_name, in place.
Preserves the type’s ordinal and every reference to it: the underlying SDK call
(rename_type) updates the til entry’s name without reallocating it.
db.types_mut().define("struct Old { int x; };")?;
db.types_mut().rename("Old", "New")?;
assert!(db.named_types().any(|t| t.name() == "New"));
assert!(!db.named_types().any(|t| t.name() == "Old"));§Errors
TypeWriteError::NoType if no type named name exists, TypeWriteError::Rejected
(e.g. TypeEditCode::DupName if new_name is already taken), or
Error::InteriorNul if either name contains a NUL byte.
Sourcepub fn forward_declare(
&mut self,
name: impl AsRef<str>,
kind: AggregateKind,
) -> Result<()>
pub fn forward_declare( &mut self, name: impl AsRef<str>, kind: AggregateKind, ) -> Result<()>
Reserve name in the local type library as an incomplete kind aggregate, with no body.
The explicit counterpart to the "struct Foo;" idiom through define:
reserves the tag without describing its members, so a later define with
a full body over the same name completes it. Until then, the type reads back as
TypeShape::Opaque, the same shape any other unresolved
or bodyless named type takes.
use idakit::types::diff::AggregateKind;
db.types_mut()
.forward_declare("idakit_fwd_probe", AggregateKind::Struct)?;
assert!(db.named_types().any(|t| t.name() == "idakit_fwd_probe"));§Errors
TypeWriteError::Rejected if the kernel refuses the declaration (e.g. name is already
taken by an incompatible type), or Error::InteriorNul if name contains a NUL byte.
Sourcepub fn edit(&mut self, name: impl Into<String>) -> TypeEdit<'_>
pub fn edit(&mut self, name: impl Into<String>) -> TypeEdit<'_>
Open the existing named type name for member surgery.
Infallible to acquire: a missing type surfaces as TypeWriteError::NoType from the first
edit, so edit(...).member(...).set_type(...) chains without an intermediate check. Each
verb is a self-contained load, mutate, and auto-save against the live type.
Examples found in repository?
189fn editing_members(idb: &mut Database) -> Result<(), Error> {
190 use idakit::types::expr;
191
192 println!("\n== types_mut: edit members ==");
193
194 idb.types_mut()
195 .define("struct edit_member_demo { int a; int b; };")?;
196
197 idb.types_mut()
198 .edit("edit_member_demo")
199 .add_member("c", expr::int32())?;
200 idb.types_mut()
201 .edit("edit_member_demo")
202 .member("a")
203 .set_type(expr::char_())?;
204 idb.types_mut()
205 .edit("edit_member_demo")
206 .member("b")
207 .rename("beta")?;
208
209 let names: Vec<String> = idb
210 .type_named("edit_member_demo")?
211 .members()
212 .unwrap_or_default()
213 .iter()
214 .map(|m| m.name.clone())
215 .collect();
216 println!(" after add + retype + rename, members: {names:?}");
217
218 // Renaming onto an existing name surfaces the structured tinfo_code.
219 match idb
220 .types_mut()
221 .edit("edit_member_demo")
222 .member("c")
223 .rename("a")
224 {
225 Err(Error::TypeWrite {
226 source: TypeWriteError::Rejected { code, .. },
227 }) => println!(" duplicate rename -> Rejected({code})"),
228 other => println!(" duplicate rename -> unexpected {other:?}"),
229 }
230
231 // Enum constants use the same cursor: add, revalue, rename.
232 idb.types_mut()
233 .define("enum edit_enum_demo { DEMO_A = 1, DEMO_B = 2 };")?;
234 idb.types_mut()
235 .edit("edit_enum_demo")
236 .add_constant("DEMO_C", 3)?;
237 idb.types_mut()
238 .edit("edit_enum_demo")
239 .constant("DEMO_A")
240 .set_value(10)?;
241 let constants: Vec<(String, u64)> = match idb.type_named("edit_enum_demo")?.shape() {
242 TypeShape::Enum { members, .. } => {
243 members.iter().map(|m| (m.name.clone(), m.value)).collect()
244 }
245 _ => Vec::new(),
246 };
247 println!(" after add + revalue, constants: {constants:?}");
248 Ok(())
249}