diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 36ddad68b8..5ab9fe33e1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -69,6 +69,8 @@ jobs: - name: Run Contiki-NG simulation tests run: | [ "$(uname)" = "Linux" ] || source ~/.bashrc + # Update Contiki-NG for current build version. + perl -pi -e 's#^EXPECTED_COOJA_VERSION =(.*)$#EXPECTED_COOJA_VERSION = 2023090701#g' contiki-ng/arch/platform/cooja/Makefile.cooja cd contiki-ng/tests/07-simulation-base # Skip MSP430 tests, no compiler installed. rm ??-*sky*.csc ??-*z1*.csc diff --git a/java/org/contikios/cooja/Cooja.java b/java/org/contikios/cooja/Cooja.java index a730338b80..82ee49577f 100644 --- a/java/org/contikios/cooja/Cooja.java +++ b/java/org/contikios/cooja/Cooja.java @@ -105,7 +105,7 @@ public class Cooja { * Version used to detect incompatibility with the Contiki-NG * build system. The format is <YYYY><MM><DD><2 digit sequence number>. */ - public static final String CONTIKI_NG_BUILD_VERSION = "2022071901"; + public static final String CONTIKI_NG_BUILD_VERSION = "2023090701"; private static final Logger logger = LoggerFactory.getLogger(Cooja.class); @@ -967,11 +967,6 @@ private static Properties getExternalToolsDefaultSettings() { settings.put("COMMAND_VAR_SEC_DATA", "[DdGg]"); settings.put("COMMAND_VAR_SEC_BSS", "[Bb]"); settings.put("COMMAND_VAR_SEC_COMMON", "[C]"); - settings.put("COMMAND_DATA_START", "^.data[ \t]d[ \t]([0-9A-Fa-f]*)[ \t]*$"); - settings.put("COMMAND_DATA_END", "^_edata[ \t]D[ \t]([0-9A-Fa-f]*)[ \t]*$"); - settings.put("COMMAND_BSS_START", "^__bss_start[ \t]B[ \t]([0-9A-Fa-f]*)[ \t]*$"); - settings.put("COMMAND_BSS_END", "^_end[ \t]B[ \t]([0-9A-Fa-f]*)[ \t]*$"); - String osName = System.getProperty("os.name").toLowerCase(); if (osName.startsWith("win")) { settings.put("PATH_C_COMPILER", "mingw32-gcc"); @@ -981,21 +976,10 @@ private static Properties getExternalToolsDefaultSettings() { settings.put("PARSE_COMMAND", "/bin/nm -aP --size-sort -S $(LIBFILE) && /bin/nm -aP $(LIBFILE)"); settings.put("COMMAND_VAR_NAME_ADDRESS_SIZE", "^[_](?[^.].*?)[ \t]
[ \t](?
[0-9a-fA-F]+)[ \t](?[0-9a-fA-F]+)"); - settings.put("COMMAND_DATA_START", "^__data_start__[ \t]D[ \t]([0-9A-Fa-f]*)"); - settings.put("COMMAND_DATA_END", "^__data_end__[ \t]D[ \t]([0-9A-Fa-f]*)"); - settings.put("COMMAND_BSS_START", "^__bss_start__[ \t]B[ \t]([0-9A-Fa-f]*)"); - settings.put("COMMAND_BSS_END", "^__bss_end__[ \t]B[ \t]([0-9A-Fa-f]*)"); } else if (osName.startsWith("mac os x")) { settings.put("PARSE_WITH_COMMAND", "true"); - settings.put("PARSE_COMMAND", "[COOJA_DIR]/tools/macos/nmandsize $(LIBFILE)"); + settings.put("PARSE_COMMAND", "symbols $(LIBFILE)"); settings.put("COMMAND_VAR_NAME_ADDRESS", "^[ \t]*([0-9A-Fa-f][0-9A-Fa-f]*)[ \t]\\(__DATA,__[^ ]*\\) external _([^ ]*)$"); - settings.put("COMMAND_DATA_START", "^DATA SECTION START: 0x([0-9A-Fa-f]+)$"); - settings.put("COMMAND_DATA_END", "^DATA SECTION END: 0x([0-9A-Fa-f]+)$"); - settings.put("COMMAND_BSS_START", "^COMMON SECTION START: 0x([0-9A-Fa-f]+)$"); - settings.put("COMMAND_BSS_END", "^COMMON SECTION END: 0x([0-9A-Fa-f]+)$"); - settings.put("COMMAND_COMMON_START", "^BSS SECTION START: 0x([0-9A-Fa-f]+)$"); - settings.put("COMMAND_COMMON_END", "^BSS SECTION END: 0x([0-9A-Fa-f]+)$"); - settings.put("COMMAND_VAR_NAME_ADDRESS_SIZE", "^\\s*0x(?
[a-fA-F0-9]+) \\(\\s*0x(?[a-fA-F0-9]+)\\) (?[A-Za-z0-9_]+) \\[.*EXT.*\\]"); settings.put("COMMAND_VAR_SEC_DATA", "(__DATA,__data)"); settings.put("COMMAND_VAR_SEC_BSS", "(__DATA,__bss)"); diff --git a/java/org/contikios/cooja/contikimote/ContikiMoteType.java b/java/org/contikios/cooja/contikimote/ContikiMoteType.java index 0712a8fc36..e8b8dbea5a 100644 --- a/java/org/contikios/cooja/contikimote/ContikiMoteType.java +++ b/java/org/contikios/cooja/contikimote/ContikiMoteType.java @@ -239,14 +239,13 @@ public boolean loadMoteFirmware(boolean vis) throws MoteTypeCreationException { if (myCoreComm != null) { throw new MoteTypeCreationException("Core communicator already used: " + myCoreComm.getClass().getName()); } - // Allocate core communicator class - final var firmwareFile = getContikiFirmwareFile(); - myCoreComm = new CoreComm(arena.scope(), firmwareFile); - /* Parse addresses using map file * or output of command specified in external tools settings (e.g. nm -a ) */ boolean useCommand = Boolean.parseBoolean(Cooja.getExternalToolsSetting("PARSE_WITH_COMMAND", "false")); + // Allocate core communicator class + final var firmwareFile = getContikiFirmwareFile(); + myCoreComm = new CoreComm(arena.scope(), firmwareFile, useCommand); var command = Cooja.getExternalToolsSetting(useCommand ? "PARSE_COMMAND" : "READELF_COMMAND"); if (command != null) { @@ -263,27 +262,17 @@ public boolean loadMoteFirmware(boolean vis) throws MoteTypeCreationException { if (useCommand) { String[] output = loadCommandData(command, firmwareFile, vis); - - dataSecParser = new CommandSectionParser( - output, - Cooja.getExternalToolsSetting("COMMAND_DATA_START"), - Cooja.getExternalToolsSetting("COMMAND_DATA_END"), + // FIXME: COMMAND_VAR_SEC_DATA & friends cannot be configured by + // the user, hardcode the values here instead. + dataSecParser = new CommandSectionParser(output, Cooja.getExternalToolsSetting("COMMAND_VAR_SEC_DATA")); - bssSecParser = new CommandSectionParser( - output, - Cooja.getExternalToolsSetting("COMMAND_BSS_START"), - Cooja.getExternalToolsSetting("COMMAND_BSS_END"), + bssSecParser = new CommandSectionParser(output, Cooja.getExternalToolsSetting("COMMAND_VAR_SEC_BSS")); - commonSecParser = new CommandSectionParser( - output, - Cooja.getExternalToolsSetting("COMMAND_COMMON_START"), - Cooja.getExternalToolsSetting("COMMAND_COMMON_END"), + commonSecParser = new CommandSectionParser(output, Cooja.getExternalToolsSetting("COMMAND_VAR_SEC_COMMON")); } else { var symbols = String.join("\n", loadCommandData(command, firmwareFile, vis)); - dataSecParser = new MapSectionParser(symbols, - myCoreComm.getDataStartAddress(), myCoreComm.getDataSize(), - myCoreComm.getBssStartAddress(), myCoreComm.getBssSize()); + dataSecParser = new MapSectionParser(symbols); } /* We first need the value of Contiki's referenceVar, which tells us the @@ -292,19 +281,13 @@ public boolean loadMoteFirmware(boolean vis) throws MoteTypeCreationException { * * This offset will be used in Cooja in the memory abstraction to match * Contiki's and Cooja's address spaces */ - Map variables = null; - if (dataSecParser.parseStartAddrAndSize()) { - variables = dataSecParser.parseSymbols(null); - } - if (bssSecParser != null && bssSecParser.parseStartAddrAndSize()) { + Map variables = dataSecParser.parseSymbols(null); + if (bssSecParser != null) { variables = bssSecParser.parseSymbols(variables); } - if (commonSecParser != null && commonSecParser.parseStartAddrAndSize()) { + if (commonSecParser != null) { variables = commonSecParser.parseSymbols(variables); } - if (variables == null) { - throw new MoteTypeCreationException("Could not parse symbols in library"); - } long offset; try { offset = myCoreComm.getReferenceAddress() - variables.get("referenceVar").addr; @@ -319,16 +302,14 @@ public boolean loadMoteFirmware(boolean vis) throws MoteTypeCreationException { var old = entry.getValue(); offsetVariables.put(entry.getKey(), new Symbol(old.type, old.name, old.addr + offset, old.size)); } - var secOffset = useCommand ? offset : 0; initialMemory = new SectionMoteMemory(offsetVariables); initialMemory.addMemorySection("data", - getMemory(dataSecParser.getDataStartAddr() + secOffset, dataSecParser.getDataSize(), offsetVariables)); - var parser = bssSecParser == null ? dataSecParser : bssSecParser; + getMemory(myCoreComm.getDataStartAddress(), myCoreComm.getDataSize(), offsetVariables)); initialMemory.addMemorySection("bss", - getMemory(parser.getBssStartAddr() + secOffset, parser.getBssSize(), offsetVariables)); + getMemory(myCoreComm.getBssStartAddress(), myCoreComm.getBssSize(), offsetVariables)); if (commonSecParser != null) { initialMemory.addMemorySection("common", - getMemory(commonSecParser.getCommonStartAddr() + secOffset, commonSecParser.getCommonSize(), offsetVariables)); + getMemory(myCoreComm.getCommonStartAddress(), myCoreComm.getCommonSize(), offsetVariables)); } getCoreMemory(initialMemory); return true; @@ -367,66 +348,22 @@ public File getExpectedFirmwareFile(String name) { /** * Abstract base class for concrete section parser class. */ - private static abstract class SectionParser { - // CommandSectionParser (OS X) takes three passes over the data. All the addresses and sizes are identical. - // MapSectionParser takes one pass over the data, and sets the data/bss variables to different values. - long dataStartAddr; - int dataSize; - long bssStartAddr; - int bssSize; - long commonStartAddr; - int commonSize; - - long getDataStartAddr() { - return dataStartAddr; - } - - int getDataSize() { - return dataSize; - } - - long getBssStartAddr() { - return bssStartAddr; - } - - int getBssSize() { - return bssSize; - } - - long getCommonStartAddr() { - return commonStartAddr; - } - - int getCommonSize() { - return commonSize; - } - - abstract boolean parseStartAddrAndSize(); - - abstract Map parseSymbols(Map inVars); + interface SectionParser { + Map parseSymbols(Map inVars); } /** * Parses Map file for section data. */ - private static class MapSectionParser extends SectionParser { + private static class MapSectionParser implements SectionParser { private final String readelfData; - MapSectionParser(String readelfData, long startData, int sizeData, long startBss, int sizeBss) { + MapSectionParser(String readelfData) { this.readelfData = readelfData; - dataStartAddr = startData; - dataSize = sizeData; - bssStartAddr = startBss; - bssSize = sizeBss; - } - - @Override - boolean parseStartAddrAndSize() { - return true; // Both startAddr and size are updated in parseSymbols() instead. } @Override - Map parseSymbols(Map inVars) { + public Map parseSymbols(Map inVars) { Map varNames = new HashMap<>(); try (var s = new Scanner(readelfData)) { s.nextLine(); // Skip first blank line. @@ -464,91 +401,24 @@ Map parseSymbols(Map inVars) { /** * Parses command output for section data. */ - private static class CommandSectionParser extends SectionParser { + private static class CommandSectionParser implements SectionParser { private final String[] mapFileData; - - private final String startRegExp; - private final String endRegExp; private final String sectionRegExp; /** * Creates SectionParser based on output of configurable command. * * @param mapFileData Map file lines as array of String - * @param startRegExp Regular expression for parsing start of section - * @param endRegExp Regular expression for parsing end of section * @param sectionRegExp Regular expression describing symbol table section identifier (e.g. '[Rr]' for readonly) * Will be used to replaced '
'in 'COMMAND_VAR_NAME_ADDRESS_SIZE' */ - CommandSectionParser(String[] mapFileData, String startRegExp, String endRegExp, String sectionRegExp) { + CommandSectionParser(String[] mapFileData, String sectionRegExp) { this.mapFileData = mapFileData; - this.startRegExp = startRegExp; - this.endRegExp = endRegExp; this.sectionRegExp = sectionRegExp; } - String[] getData() { - return mapFileData; - } - - @Override - boolean parseStartAddrAndSize() { - // FIXME: Adjust this code to mirror the optimized method in MapSectionParser. - if (startRegExp == null || startRegExp.isEmpty()) { - dataStartAddr = bssStartAddr = commonStartAddr = -1; - } else { - long result; - String retString = null; - Pattern pattern = Pattern.compile(startRegExp); - for (String line : getData()) { - Matcher matcher = pattern.matcher(line); - if (matcher.find()) { - retString = matcher.group(1); - break; - } - } - - if (retString == null || retString.isEmpty()) { - result = -1; - } else { - result = Long.parseUnsignedLong(retString.trim(), 16); - } - - dataStartAddr = bssStartAddr = commonStartAddr = result; - } - - if (dataStartAddr < 0 || endRegExp == null || endRegExp.isEmpty()) { - dataSize = bssSize = commonSize = -1; - return false; - } - - long end; - String retString = null; - Pattern pattern = Pattern.compile(endRegExp); - for (String line : getData()) { - Matcher matcher = pattern.matcher(line); - if (matcher.find()) { - retString = matcher.group(1); - break; - } - } - - if (retString == null || retString.isEmpty()) { - end = -1; - } else { - end = Long.parseUnsignedLong(retString.trim(), 16); - } - - if (end < 0) { - dataSize = bssSize = commonSize = -1; - return false; - } - dataSize = bssSize = commonSize = (int) (end - getDataStartAddr()); - return dataStartAddr >= 0 && dataSize > 0; - } - @Override - Map parseSymbols(Map inVars) { + public Map parseSymbols(Map inVars) { if (inVars != null) { return inVars; } @@ -557,7 +427,7 @@ Map parseSymbols(Map inVars) { Pattern pattern = Pattern.compile( Cooja.getExternalToolsSetting("COMMAND_VAR_NAME_ADDRESS_SIZE") .replace("
", Pattern.quote(sectionRegExp))); - for (String line : getData()) { + for (String line : mapFileData) { Matcher matcher = pattern.matcher(line); if (matcher.find()) { diff --git a/java/org/contikios/cooja/contikimote/CoreComm.java b/java/org/contikios/cooja/contikimote/CoreComm.java index d04fe9fd74..97646a85df 100644 --- a/java/org/contikios/cooja/contikimote/CoreComm.java +++ b/java/org/contikios/cooja/contikimote/CoreComm.java @@ -33,6 +33,7 @@ import java.lang.foreign.Linker; import java.lang.foreign.SegmentScope; import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; /** @@ -44,13 +45,21 @@ class CoreComm { private final SymbolLookup symbols; private final MethodHandle coojaTick; + + private final long dataStart; + private final int dataSize; + private final long bssStart; + private final int bssSize; + private final long commonStart; + private final int commonSize; /** * Loads library libFile with a scope. * * @param scope Scope to load the library file in * @param libFile Library file + * @param queryContiki Call helper functions in Contiki-NG (macOS) */ - CoreComm(SegmentScope scope, File libFile) { + CoreComm(SegmentScope scope, File libFile, boolean queryContiki) { symbols = SymbolLookup.libraryLookup(libFile.getAbsolutePath(), scope); var linker = Linker.nativeLinker(); coojaTick = linker.downcallHandle(symbols.find("cooja_tick").get(), @@ -63,6 +72,56 @@ class CoreComm { } catch (Throwable e) { throw new RuntimeException("Calling cooja_init failed: " + e.getMessage(), e); } + if (queryContiki) { + var getBssStart = linker.downcallHandle(symbols.find("cooja_bss_start").get(), + FunctionDescriptor.of(ValueLayout.JAVA_LONG)); + try { + bssStart = (long)getBssStart.invokeExact(); + } catch (Throwable e) { + throw new RuntimeException("Calling cooja_bss_start failed: " + e.getMessage(), e); + } + var getBssSize = linker.downcallHandle(symbols.find("cooja_bss_size").get(), + FunctionDescriptor.of(ValueLayout.JAVA_INT)); + try { + bssSize = (int)getBssSize.invokeExact(); + } catch (Throwable e) { + throw new RuntimeException("Calling cooja_bss_size failed: " + e.getMessage(), e); + } + var getDataStart = linker.downcallHandle(symbols.find("cooja_data_start").get(), + FunctionDescriptor.of(ValueLayout.JAVA_LONG)); + try { + dataStart = (long)getDataStart.invokeExact(); + } catch (Throwable e) { + throw new RuntimeException("Calling cooja_data_start failed: " + e.getMessage(), e); + } + var getDataSize = linker.downcallHandle(symbols.find("cooja_data_size").get(), + FunctionDescriptor.of(ValueLayout.JAVA_INT)); + try { + dataSize = (int)getDataSize.invokeExact(); + } catch (Throwable e) { + throw new RuntimeException("Calling cooja_data_size failed: " + e.getMessage(), e); + } + var getCommonStart = linker.downcallHandle(symbols.find("cooja_common_start").get(), + FunctionDescriptor.of(ValueLayout.JAVA_LONG)); + try { + commonStart = (long)getCommonStart.invokeExact(); + } catch (Throwable e) { + throw new RuntimeException("Calling cooja_common_start failed: " + e.getMessage(), e); + } + var getCommonSize = linker.downcallHandle(symbols.find("cooja_common_size").get(), + FunctionDescriptor.of(ValueLayout.JAVA_INT)); + try { + commonSize = (int)getCommonSize.invokeExact(); + } catch (Throwable e) { + throw new RuntimeException("Calling cooja_common_size failed: " + e.getMessage(), e); + } + } else { + dataStart = symbols.find("cooja_dataStart").get().address(); + dataSize = (int)symbols.find("cooja_dataSize").get().address(); + bssStart = symbols.find("cooja_bssStart").get().address(); + bssSize = (int)symbols.find("cooja_bssSize").get().address(); + commonStart = commonSize = 0; + } } /** @@ -87,29 +146,41 @@ long getReferenceAddress() { * Returns the absolute address of the start of the data section. */ long getDataStartAddress() { - return symbols.find("cooja_dataStart").get().address(); + return dataStart; } /** * Returns the size of the data section. */ int getDataSize() { - var dataSize = symbols.find("cooja_dataSize").get(); - return (int)dataSize.address(); + return dataSize; } /** * Returns the absolute address of the start of the bss section. */ long getBssStartAddress() { - return symbols.find("cooja_bssStart").get().address(); + return bssStart; } /** * Returns the size of the bss section. */ int getBssSize() { - var bssSize = symbols.find("cooja_bssSize").get(); - return (int)bssSize.address(); + return bssSize; + } + + /** + * Returns the absolute address of the start of the common section. + */ + long getCommonStartAddress() { + return commonStart; + } + + /** + * Returns the size of the common section. + */ + int getCommonSize() { + return commonSize; } } diff --git a/java/org/contikios/cooja/dialogs/ExternalToolsDialog.java b/java/org/contikios/cooja/dialogs/ExternalToolsDialog.java index 28ee75cf26..68889cd746 100644 --- a/java/org/contikios/cooja/dialogs/ExternalToolsDialog.java +++ b/java/org/contikios/cooja/dialogs/ExternalToolsDialog.java @@ -73,9 +73,6 @@ public class ExternalToolsDialog extends JDialog { "PARSE_COMMAND", "COMMAND_VAR_NAME_ADDRESS_SIZE", - "COMMAND_DATA_START", "COMMAND_DATA_END", - "COMMAND_BSS_START", "COMMAND_BSS_END", - "COMMAND_COMMON_START", "COMMAND_COMMON_END", "HIDE_WARNINGS" }; diff --git a/tools/macos/nmandsize b/tools/macos/nmandsize deleted file mode 100755 index 84ae24ddd6..0000000000 --- a/tools/macos/nmandsize +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -if ! command -v gawk &> /dev/null; then - >&2 echo "The command gawk is not found. Please install gawk!" - exit 1 -fi - -symbols $1 - -S="$(size -x -m -l $1)" - -parse() ( - echo "$S" | - gawk --non-decimal-data '/^Segment/ {s=$2} s=="__DATA:" && $2=="'$1'" \ - {printf "%s %s 0x%x\n",$5,$3,($3+$5)}' | - (read start size end; - echo "$2 START: $start"; - echo "$2 SIZE: $size"; - echo "$2 END: $end") -) - -parse __data: "DATA SECTION" -parse __bss: "BSS SECTION" -parse __common: "COMMON SECTION"