Created
August 1, 2025 12:26
-
-
Save nift4/f9e411efed17fd431859b154708fda27 to your computer and use it in GitHub Desktop.
import linux kernel headers into ghidra
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 4b5e234b24d85eccc12978bee09b4e71b4974827 Mon Sep 17 00:00:00 2001 | |
From: nift4 <[email protected]> | |
Date: Sun, 19 Nov 2023 09:56:28 +0100 | |
Subject: [PATCH] fixes for ghidra | |
--- | |
Makefile | 2 +- | |
include/linux/percpu-refcount.h | 4 ++-- | |
include/linux/workqueue.h | 2 +- | |
3 files changed, 4 insertions(+), 4 deletions(-) | |
diff --git a/Makefile b/Makefile | |
index fe56427c6a65..c23ee685059c 100644 | |
--- a/Makefile | |
+++ b/Makefile | |
@@ -636,7 +636,7 @@ endif | |
# Defaults to vmlinux, but the arch makefile usually adds further targets | |
all: vmlinux | |
-KBUILD_CFLAGS += $(call cc-option,-fno-PIE) | |
+KBUILD_CFLAGS += $(call cc-option,-fno-PIE) -save-temps=obj | |
KBUILD_AFLAGS += $(call cc-option,-fno-PIE) | |
CFLAGS_GCOV := -fprofile-arcs -ftest-coverage -fno-tree-loop-im $(call cc-disable-warning,maybe-uninitialized,) | |
CFLAGS_KCOV := $(call cc-option,-fsanitize-coverage=trace-pc,) | |
diff --git a/include/linux/percpu-refcount.h b/include/linux/percpu-refcount.h | |
index 3a481a49546e..dc24e735d50a 100644 | |
--- a/include/linux/percpu-refcount.h | |
+++ b/include/linux/percpu-refcount.h | |
@@ -56,8 +56,8 @@ typedef void (percpu_ref_func_t)(struct percpu_ref *); | |
/* flags set in the lower bits of percpu_ref->percpu_count_ptr */ | |
enum { | |
- __PERCPU_REF_ATOMIC = 1LU << 0, /* operating in atomic mode */ | |
- __PERCPU_REF_DEAD = 1LU << 1, /* (being) killed */ | |
+ __PERCPU_REF_ATOMIC = 1UL << 0, /* operating in atomic mode */ | |
+ __PERCPU_REF_DEAD = 1UL << 1, /* (being) killed */ | |
__PERCPU_REF_ATOMIC_DEAD = __PERCPU_REF_ATOMIC | __PERCPU_REF_DEAD, | |
__PERCPU_REF_FLAG_BITS = 2, | |
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h | |
index b95c511139b9..4141c00f2387 100644 | |
--- a/include/linux/workqueue.h | |
+++ b/include/linux/workqueue.h | |
@@ -82,7 +82,7 @@ enum { | |
WORK_OFFQ_POOL_SHIFT = WORK_OFFQ_FLAG_BASE + WORK_OFFQ_FLAG_BITS, | |
WORK_OFFQ_LEFT = BITS_PER_LONG - WORK_OFFQ_POOL_SHIFT, | |
WORK_OFFQ_POOL_BITS = WORK_OFFQ_LEFT <= 31 ? WORK_OFFQ_LEFT : 31, | |
- WORK_OFFQ_POOL_NONE = (1LU << WORK_OFFQ_POOL_BITS) - 1, | |
+ WORK_OFFQ_POOL_NONE = (1UL << WORK_OFFQ_POOL_BITS) - 1, | |
/* convenience constants */ | |
WORK_STRUCT_FLAG_MASK = (1UL << WORK_STRUCT_FLAG_BITS) - 1, | |
-- | |
2.42.0 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env kotlin -howtorun .main.kts | |
@file:Repository("https://repo1.maven.org/maven2/") | |
@file:DependsOn("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1-Beta") | |
@file:DependsOn("org.json:json:20240303") | |
import kotlinx.coroutines.* | |
import org.json.JSONObject | |
import java.io.File | |
import java.nio.file.LinkOption | |
import java.nio.file.Path | |
import java.util.* | |
import java.util.concurrent.Executors | |
import java.util.concurrent.atomic.AtomicInteger | |
import kotlin.io.path.* | |
val taskCount = 16 | |
val tmpDir = File("/home/nick/tmp") | |
val ctags = "ctags" | |
val debug = true | |
suspend inline fun <A, B> Iterable<A>.forEachParallel(crossinline f: suspend (A) -> B) = coroutineScope { | |
map { async { f(it) } }.awaitAll() | |
} | |
inline fun <A, B> A.mapForEach(collection: Collection<B>, block: A.(B) -> A): A { | |
var a = this | |
collection.forEach { a = a.block(it) } | |
return a | |
} | |
val context = Executors.newFixedThreadPool(taskCount).asCoroutineDispatcher() | |
@OptIn(ExperimentalPathApi::class) | |
fun main(args: Array<String>) { | |
println("i2ghidra 1.0.0 by https://github.com/nift4") | |
runBlocking { | |
val versionString = listOf(ctags, "--version").runCommand(stderr = true).waitForAndGetStdout() | |
if (versionString.contains("Universal Ctags 5.")) { | |
// debian's universal-ctags breaks parsing of gro_receive_t which in turn breaks removal of call_gro_receive | |
println("Your version of Universal Ctags is too old. There are known bugs that impact this script in " + | |
"this version. Please strongly consider updating.") | |
} else if (!versionString.contains("Universal Ctags")) { | |
println("Please consider using Universal Ctags. This script was only tested with Universal Ctags.") | |
} | |
} | |
if (args.size != 2) { | |
println("Wrong number of arguments!") | |
println("Usage:") | |
println("kotlinc -script i2ghidra.main.kts INPUT_FOLDER OUTPUT_FOLDER") | |
return | |
} | |
val rootTree = Path(args[0]).absolute() | |
if (!rootTree.exists()) { | |
println("Input folder ${args[0]} does not exist") | |
return | |
} | |
if (!rootTree.isDirectory() || !rootTree.isReadable()) { | |
println("Input folder ${args[0]} is not a readable directory") | |
return | |
} | |
val outDir = Path(args[1]).absolute() | |
outDir.deleteRecursively() | |
outDir.createDirectories() | |
if (!outDir.exists()) { | |
println("Output folder ${args[1]} does not exist and cannot be created") | |
return | |
} | |
if (!outDir.isDirectory() || !outDir.isReadable() || !outDir.isWritable()) { | |
println("Output folder ${args[1]} is not a readable and writeable directory") | |
return | |
} | |
if (outDir.contains(rootTree)) { | |
println("Output folder must not contain input folder") | |
return | |
} | |
print("Currently scanning input folder... ") | |
val files = rootTree.walk().filter { | |
it.isRegularFile(LinkOption.NOFOLLOW_LINKS) && !outDir.contains(it) | |
&& it.extension == "i" && it.name.startsWith(".tmp_") | |
}.toList() | |
println("Done!") | |
runBlocking { | |
val counter = AtomicInteger() | |
val job = launch(context) { | |
files.forEachParallel { | |
val abs = it.absolute() | |
val fileInOutDir = outDir.resolve(abs.relativeTo(rootTree)) | |
processFile(abs, fileInOutDir.parent.resolve(abs.name.substring(".tmp_".length))) | |
counter.incrementAndGet() | |
} | |
} | |
val jobCount = "Currently processing ${files.size} files with $taskCount threads... " | |
val padLen = files.size.toString().length | |
while (job.isActive) { | |
print(jobCount + "Completed: ${counter.get().toString().padStart(padLen, '0')}\r") | |
try { | |
withTimeout(100L) { | |
job.join() | |
} | |
} catch (_: TimeoutCancellationException) { | |
} | |
} | |
job.join() | |
println(jobCount + "Done!") | |
} | |
println("Done! You can now import the generated .h files into Ghidra.") | |
} | |
val commonFixes = listOf( | |
Pair("extern __typeof__(unsigned long [16384/sizeof(long)]) irq_stack;", "extern unsigned long irq_stack[16384/sizeof(long)];"), | |
Pair("[] = \"\\\"\" \"i2c-%d #%u a=%03x f=%04x l=%u [%*phD]\" \"\\\", \" \"REC->adapter_nr, REC->msg_nr, REC->addr, REC->flags, REC->len, REC->len, __get_dynamic_array(buf)\";", "[] = \"\\\"i2c-%d #%u a=%03x f=%04x l=%u [%*phD]\\\", REC->adapter_nr, REC->msg_nr, REC->addr, REC->flags, REC->len, REC->len, __get_dynamic_array(buf)\";"), | |
Pair("[] = \"\\\"\" \"i2c-%d #%u a=%03x f=%04x l=%u\" \"\\\", \" \"REC->adapter_nr, REC->msg_nr, REC->addr, REC->flags, REC->len\";", "[] = \"\\\"i2c-%d #%u a=%03x f=%04x l=%u\\\", REC->adapter_nr, REC->msg_nr, REC->addr, REC->flags, REC->len\";"), | |
Pair("[] = \"\\\"\" \"i2c-%d n=%u ret=%d\" \"\\\", \" \"REC->adapter_nr, REC->nr_msgs, REC->ret\";", "[] = \"\\\"i2c-%d n=%u ret=%d\\\", REC->adapter_nr, REC->nr_msgs, REC->ret\";"), | |
Pair("[] = \"\\\"\" \"i2c-%d a=%03x f=%04x c=%x %s l=%u [%*phD]\" \"\\\", \" \"REC->adapter_nr, REC->addr, REC->flags, REC->command, __print_symbolic(REC->protocol, { 0, \\\"QUICK\\\" }, { 1, \\\"BYTE\\\" }, { 2, \\\"BYTE_DATA\\\" }, { 3, \\\"WORD_DATA\\\" }, { 4, \\\"PROC_CALL\\\" }, { 5, \\\"BLOCK_DATA\\\" }, { 6, \\\"I2C_BLOCK_BROKEN\\\" }, { 7, \\\"BLOCK_PROC_CALL\\\" }, { 8, \\\"I2C_BLOCK_DATA\\\" }), REC->len, REC->len, REC->buf\";", "[] = \"\\\"i2c-%d a=%03x f=%04x c=%x %s l=%u [%*phD]\\\", REC->adapter_nr, REC->addr, REC->flags, REC->command, __print_symbolic(REC->protocol, { 0, \\\"QUICK\\\" }, { 1, \\\"BYTE\\\" }, { 2, \\\"BYTE_DATA\\\" }, { 3, \\\"WORD_DATA\\\" }, { 4, \\\"PROC_CALL\\\" }, { 5, \\\"BLOCK_DATA\\\" }, { 6, \\\"I2C_BLOCK_BROKEN\\\" }, { 7, \\\"BLOCK_PROC_CALL\\\" }, { 8, \\\"I2C_BLOCK_DATA\\\" }), REC->len, REC->len, REC->buf\";"), | |
Pair("[] = \"\\\"\" \"i2c-%d a=%03x f=%04x c=%x %s\" \"\\\", \" \"REC->adapter_nr, REC->addr, REC->flags, REC->command, __print_symbolic(REC->protocol, { 0, \\\"QUICK\\\" }, { 1, \\\"BYTE\\\" }, { 2, \\\"BYTE_DATA\\\" }, { 3, \\\"WORD_DATA\\\" }, { 4, \\\"PROC_CALL\\\" }, { 5, \\\"BLOCK_DATA\\\" }, { 6, \\\"I2C_BLOCK_BROKEN\\\" }, { 7, \\\"BLOCK_PROC_CALL\\\" }, { 8, \\\"I2C_BLOCK_DATA\\\" })\";", "[] = \"\\\"i2c-%d a=%03x f=%04x c=%x %s\\\", REC->adapter_nr, REC->addr, REC->flags, REC->command, __print_symbolic(REC->protocol, { 0, \\\"QUICK\\\" }, { 1, \\\"BYTE\\\" }, { 2, \\\"BYTE_DATA\\\" }, { 3, \\\"WORD_DATA\\\" }, { 4, \\\"PROC_CALL\\\" }, { 5, \\\"BLOCK_DATA\\\" }, { 6, \\\"I2C_BLOCK_BROKEN\\\" }, { 7, \\\"BLOCK_PROC_CALL\\\" }, { 8, \\\"I2C_BLOCK_DATA\\\" })\";"), | |
Pair("[] = \"\\\"\" \"i2c-%d a=%03x f=%04x c=%x %s %s res=%d\" \"\\\", \" \"REC->adapter_nr, REC->addr, REC->flags, REC->command, __print_symbolic(REC->protocol, { 0, \\\"QUICK\\\" }, { 1, \\\"BYTE\\\" }, { 2, \\\"BYTE_DATA\\\" }, { 3, \\\"WORD_DATA\\\" }, { 4, \\\"PROC_CALL\\\" }, { 5, \\\"BLOCK_DATA\\\" }, { 6, \\\"I2C_BLOCK_BROKEN\\\" }, { 7, \\\"BLOCK_PROC_CALL\\\" }, { 8, \\\"I2C_BLOCK_DATA\\\" }), REC->read_write == 0 ? \\\"wr\\\" : \\\"rd\\\", REC->res\";", "[] = \"\\\"i2c-%d a=%03x f=%04x c=%x %s %s res=%d\\\", REC->adapter_nr, REC->addr, REC->flags, REC->command, __print_symbolic(REC->protocol, { 0, \\\"QUICK\\\" }, { 1, \\\"BYTE\\\" }, { 2, \\\"BYTE_DATA\\\" }, { 3, \\\"WORD_DATA\\\" }, { 4, \\\"PROC_CALL\\\" }, { 5, \\\"BLOCK_DATA\\\" }, { 6, \\\"I2C_BLOCK_BROKEN\\\" }, { 7, \\\"BLOCK_PROC_CALL\\\" }, { 8, \\\"I2C_BLOCK_DATA\\\" }), REC->read_write == 0 ? \\\"wr\\\" : \\\"rd\\\", REC->res\";") | |
) | |
val prefix = "#define __typeof__(a) a\n#define _Static_assert(a)\ntypedef unsigned long long __uint128_t;\n" | |
private suspend fun processFile(file: Path, outFile: Path) { | |
var text = file.readText(Charsets.UTF_8) | |
text = removeComments(text) | |
text = removeAttributes(text) // TODO try using #define instead of this | |
// If your source is formatted in a way that ctags is unable to properly inspect, please enable one of these proper | |
// formatting tools and disable the (in comparison very performant) DIY formatter made to fit linux kernel style. | |
//text = runAstyle(text) | |
//text = runClangFormat(text) | |
text = text.replace("{ ", "{\n").replace("} ", "}\n").replace("; ", ";\n") | |
text = removeStrayCommas(text) | |
text = runDiyFormatter(text) | |
text = removeTypeofSelf(text) | |
if (debug) { | |
val outFile2 = outFile.resolveSibling(outFile.name + ".DEBUG") | |
val tw = text | |
coroutineScope { | |
launch(Dispatchers.IO) { | |
outFile2.createParentDirectories() | |
outFile2.writeText(tw, Charsets.UTF_8) | |
} | |
} | |
} | |
val tags = runCtags(text) | |
text = removeMethodBodiesUsingCtags(text, tags) | |
text = text.mapForEach(commonFixes) { replace(it.first, it.second) } | |
text = prefix + text | |
withContext(Dispatchers.IO) { | |
outFile.createParentDirectories() | |
outFile.writeText(text, Charsets.UTF_8) | |
} | |
} | |
private fun removeComments(text: String): String { | |
return text.split('\n').filter { !it.startsWith('#') }.joinToString("\n") | |
} | |
val attr = "__attribute__" | |
val relevantChars = charArrayOf('(', ')') | |
private fun removeAttributes(text: String): String { | |
return text.split(';').mapIndexed { linePos, inLine -> | |
var attrPos = inLine.indexOf(attr) | |
if (attrPos == -1) return@mapIndexed inLine | |
var line = inLine | |
var relevantCharPos = line.indexOfAny(relevantChars) | |
var pos = relevantCharPos.coerceAtMost(attrPos) | |
var lastAttrStartPos = -1 | |
var initiallyOpen = 0 | |
var open = 0 | |
while ((lastAttrStartPos != -1 || attrPos != -1) && pos != -1 && pos < line.length) { | |
val char = line[pos] | |
if (char == '(') { | |
open++ | |
pos++ | |
} else if (char == ')') { | |
open-- | |
if (lastAttrStartPos != -1 && open == initiallyOpen) { | |
line = line.removeRange(lastAttrStartPos..pos) | |
// if we remove 2 items, we need to move pos back by 2 to stay at the same character | |
pos = lastAttrStartPos | |
attrPos = line.indexOf(attr, startIndex = pos) | |
relevantCharPos = -1 | |
lastAttrStartPos = -1 | |
} else pos++ | |
} else if (char == '_') { | |
if (pos == attrPos) { | |
lastAttrStartPos = pos | |
pos += attr.length | |
attrPos = line.indexOf(attr, startIndex = pos) | |
initiallyOpen = open | |
} else pos++ | |
} else throw IllegalStateException("internal error in removeAttributes line $linePos, got $char") | |
if (relevantCharPos <= pos) { // if attrPos was before ( last time, no need to recalculate | |
relevantCharPos = line.indexOfAny(relevantChars, startIndex = pos) | |
} | |
pos = if (attrPos != -1) relevantCharPos.coerceAtMost(attrPos) else relevantCharPos | |
} | |
line | |
}.joinToString(";") | |
} | |
private fun List<String>.runCommand(stdout: Boolean = false, stderr: Boolean = false, | |
workingDir: File = Path("").absolute().toFile()): Process { | |
return ProcessBuilder(this) | |
.directory(workingDir) | |
.redirectOutput(if (stdout) ProcessBuilder.Redirect.INHERIT else ProcessBuilder.Redirect.PIPE) | |
.redirectError(if (stderr) ProcessBuilder.Redirect.INHERIT else ProcessBuilder.Redirect.PIPE) | |
.start() | |
} | |
private suspend fun Process.waitForAndGetStdout(): String { | |
val stdout = inputReader().readText() | |
runInterruptible { | |
waitFor() | |
} | |
if (isAlive) { | |
destroyForcibly() | |
} | |
return stdout | |
} | |
private fun mktemp(text: String): File { | |
return File.createTempFile("tags_", ".h", tmpDir).apply { | |
deleteOnExit() | |
writeText(text, charset = Charsets.UTF_8) | |
} | |
} | |
/* | |
private suspend fun runClangFormat(text: String): String { | |
val temp = mktemp(text) | |
return listOf( | |
"clang-format", "-style={BasedOnStyle: WebKit, " + | |
"PenaltyReturnTypeOnItsOwnLine: 0, " + | |
"AlwaysBreakAfterReturnType: None, " + | |
"AllowShortFunctionsOnASingleLine: None, " + | |
"AllowShortLambdasOnASingleLine: None, " + | |
"BreakBeforeBraces: Allman}", temp.absolutePath | |
).runCommand(stderr = true).waitForAndGetStdout() | |
} | |
private suspend fun runAstyle(text: String): String { | |
return listOf("astyle", "-q").runCommand(stderr = true).apply { | |
outputWriter().apply { | |
write(text) | |
close() | |
} | |
}.waitForAndGetStdout() | |
} | |
*/ | |
private suspend fun runCtags(text: String): List<JSONObject> { | |
val temp = mktemp(text) | |
val tags = listOf( | |
ctags, "--fields=+ne", "-o", "-", "--sort=no", "--c-types=fp", "--output-format=json", | |
"--language-force=c", temp.absolutePath | |
).runCommand(stderr = true).waitForAndGetStdout() | |
return tags.split('\n').filter { it.isNotBlank() }.map { JSONObject(it.trim()) }.toList() | |
} | |
private fun <T> MutableList<T>.rangeReplace(from: Int, to: Int, new: List<T>) { | |
subList(from, to).apply { | |
clear() | |
addAll(new) | |
} | |
} | |
// ctags does not seem to support attributes such as "inline" and return type on another line than the function's name | |
// this heuristic works around this limitation | |
private fun runDiyFormatter(text: String): String { | |
val lines = text.split('\n').toMutableList() | |
var i = 0 | |
while (i < lines.size) { | |
val line = lines[i] | |
if (!line.contains(inlineRegex) || line.contains('{') || line.contains(';')) { | |
i++ | |
continue | |
} | |
val s = i | |
var newText = lines[i] | |
i++ | |
while (i < lines.size) { | |
newText += " " + lines[i] | |
if (newText.contains('{') || newText.contains(';')) break | |
i++ | |
} | |
lines.rangeReplace(s, i + 1, listOf(newText)) | |
i = s + 1 | |
} | |
return lines.joinToString("\n") | |
} | |
val inlineRegex = Regex("\\sinline\\s") | |
private fun removeMethodBodiesUsingCtags(inText: String, tags: List<JSONObject>): String { | |
var diff = 0 | |
return LinkedList(inText.split('\n')).mapForEach(tags) { | |
if (it.has("scope") && it.getString("scope").contains("anon")) return@mapForEach this | |
val start = (it.getInt("line") - 1) // one line above { | |
val end = it.getInt("end") // line of } | |
val pattern = Regex(it.getString("pattern").mapForEach(listOf("*", "{", "(", ")", "[", "]", "+")) { | |
c -> replace(c, "\\$c") }.run { substring(1, length - 1) }, | |
setOf(RegexOption.MULTILINE, RegexOption.UNIX_LINES)) | |
val method = subList(start - diff, end - diff).joinToString("\n") | |
val pos = pattern.find(method)?.range | |
?: throw IllegalStateException("didn't find ctags pattern $pattern in string, why?") | |
val prefix = method.substring(0, pos.first) | |
val sp = method.substring(pos.first).split('{', limit = 2) | |
val header = sp[0] | |
val isInline = header.contains(inlineRegex) | |
if (sp.size <= 1 && !isInline) { | |
return@mapForEach this // not inline, no method body, no need to change anything | |
} | |
val new1 = if (isInline) "" /* remove inline method */ else /* remove method body */ "$header;" | |
val new = (prefix + new1).split("\n") | |
rangeReplace(start - diff, end - diff, new) | |
diff += ((end - start) - new.size) | |
return@mapForEach this | |
}.joinToString("\n") | |
} | |
val strayCommaRegex = Regex(",(\\s*\\})", setOf(RegexOption.MULTILINE, RegexOption.UNIX_LINES)) | |
private fun removeStrayCommas(text: String): String { | |
return text.replace(strayCommaRegex) { it.groupValues[1] } | |
} | |
val typeofSelfRegex = Regex("extern typeof\\((\\S+)\\) \\1;", setOf(RegexOption.CANON_EQ)) | |
private fun removeTypeofSelf(text: String): String { | |
return text.replace(typeofSelfRegex, "") | |
} | |
context.use { | |
main(args) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//TODO write a description for this script | |
//stolen from reddit, idk where from sorry, but it ain't mine | |
//@author | |
//@category _NEW_ | |
//@keybinding | |
//@menupath | |
//@toolbar | |
import ghidra.app.script.GhidraScript; | |
import ghidra.app.cmd.function.*; | |
import ghidra.program.model.mem.*; | |
import ghidra.program.model.lang.*; | |
import ghidra.program.model.pcode.*; | |
import ghidra.program.model.util.*; | |
import ghidra.program.model.reloc.*; | |
import ghidra.program.model.data.*; | |
import ghidra.program.model.block.*; | |
import ghidra.program.model.symbol.*; | |
import ghidra.program.model.scalar.*; | |
import ghidra.program.model.listing.*; | |
import ghidra.program.model.address.*; | |
public class MatchExportsToHeader extends GhidraScript { | |
public void run() throws Exception { | |
var dmgr = currentProgram.getDataTypeManager(); | |
var symTable = currentProgram.getSymbolTable(); | |
var iter = dmgr.getAllDataTypes(); | |
while (iter.hasNext()) { | |
var type = iter.next(); | |
if (!(type instanceof FunctionDefinition)) | |
continue; | |
// println(type.getName()); | |
var matches = symTable.getGlobalSymbols(type.getName()); | |
println("match found: " + type.getName()); | |
for (var sym : matches) { | |
ApplyFunctionSignatureCmd cmd = new ApplyFunctionSignatureCmd(sym.getAddress(), | |
(FunctionDefinition) type, SourceType.IMPORTED); | |
cmd.applyTo(currentProgram); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment