diff --git a/.gitignore b/.gitignore index e37ce9534..f5ee135e6 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,7 @@ client/traces/* armsrc/TEMP EMV/* tools/mf_nonce_brute/* tools/andrew/* +tools/jtag_openocd/openocd_configuration ppls patches/* *- Copy.* @@ -73,3 +74,4 @@ client/lualibs/mf_default_keys.lua client/lualibs/pm3_cmd.lua # recompiled fpga_version_info.c + diff --git a/.travis.yml b/.travis.yml index b81af3d97..723d1c1a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ compiler: gcc matrix: include: - os: osx - osx_image: xcode9.1 # OS X 10.13.1 + osx_image: xcode9.2 # OS X 10.13 - os: linux dist: xenial sudo: required diff --git a/CHANGELOG.md b/CHANGELOG.md index 95930c002..001a53a34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] - Fix 'hf mf sim' - wrong access rights to write key B in trailer (@McEloff) + - Add option -i to flasher to query Pm3 for its memory size (@doegox) + - Add support for flashing 512K units (@slurdge) + - Add a simple python tool to check the elf sizes (@slurdge) + - Change: new keys for Vigik badges in default_keys.dict (@luminouw) - Add 'hw standalone' to jump to standalone mode from command line or script (@doegox) - Add to 'hf 14a apdu' print apdu and compose apdu (@merlokk) - Change: buggy 'mem read' removed, 'mem save' renamed 'mem dump', can now display too (@doegox) diff --git a/README.md b/README.md index e3be68472..50813868e 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,9 @@ This repo is based on iceman fork for Proxmark3. It is dedicated to bringing the most out of the new features for Proxmark3 RDV4.0 new hardware and design. Note that it also supports other Proxmark3 platforms as well! -[![Build status](https://ci.appveyor.com/api/projects/status/ct5blik2wa96bv0x/branch/master?svg=true)](https://ci.appveyor.com/project/iceman1001/proxmark3-ji4wj/branch/master) -[![Latest release](https://img.shields.io/github/release/RfidResearchGroup/proxmark3.svg)](https://github.com/RfidResearchGroup/proxmark3/releases/latest) +| Releases | Linux & OSX CI | Windows CI | +| ------------------- |:-------------------:| -------------------:| +| [![Latest release](https://img.shields.io/github/release/RfidResearchGroup/proxmark3.svg)](https://github.com/RfidResearchGroup/proxmark3/releases/latest) | [![Build status](https://travis-ci.org/RfidResearchGroup/proxmark3.svg?branch=master)](https://travis-ci.org/RfidResearchGroup/proxmark3) | [![Build status](https://ci.appveyor.com/api/projects/status/b4gwrhq3nc876cuu/branch/master?svg=true)](https://ci.appveyor.com/project/RfidResearchGroup/proxmark3/branch/master) | --- diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index f905fc536..734513b54 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -13,6 +13,8 @@ #define MAX_ISO14A_TIMEOUT 524288 static uint32_t iso14a_timeout; +// if iso14443a not active - transmit/receive dont try to execute +static bool iso14443a_active = false; uint8_t colpos = 0; int rsamples = 0; @@ -1551,6 +1553,9 @@ void PrepareDelayedTransfer(uint16_t delay) { //------------------------------------------------------------------------------------- static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing) { + if (!iso14443a_active) + return; + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); if (timing) { @@ -1578,10 +1583,20 @@ static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing volatile uint8_t b; uint16_t c = 0; + uint32_t sendtimer = GetTickCount(); + uint32_t cntr = 0; while (c < len) { if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { AT91C_BASE_SSC->SSC_THR = cmd[c++]; + cntr = 0; + } else { + if (cntr++ > 1000) { + cntr = 0; + if (GetTickCount() - sendtimer > 100) + break; + } } + //iceman test if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { b = (uint16_t)(AT91C_BASE_SSC->SSC_RHR); @@ -1923,6 +1938,9 @@ bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_Start static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receivedResponsePar, uint16_t offset) { uint32_t c = 0; + if (!iso14443a_active) + return false; + // Set FPGA mode to "reader listen mode", no modulation (listen // only, since we are receiving, not transmitting). // Signal field is on with the appropriate LED @@ -1937,6 +1955,7 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receive (void)b; uint32_t timeout = iso14a_get_timeout(); + uint32_t receive_timer = GetTickCount(); for (;;) { WDT_HIT(); @@ -1949,7 +1968,12 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receive return false; } } + + // timeout already in ms + 100ms guard time + if (GetTickCount() - receive_timer > timeout + 100) + break; } + return false; } void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing) { @@ -2354,6 +2378,14 @@ void iso14443a_setup(uint8_t fpga_minor_mode) { UartReset(); NextTransferTime = 2 * DELAY_ARM2AIR_AS_READER; iso14a_set_timeout(1060); // 106 * 10ms default + + iso14443a_active = true; +} + +void iso14443a_off() { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + iso14443a_active = false; } /* Peter Fillmore 2015 @@ -2558,9 +2590,8 @@ void ReaderIso14443a(PacketCommandNG *c) { return; OUT: - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + iso14443a_off(); set_tracing(false); - LEDsoff(); } // Determine the distance between two nonces. @@ -2854,8 +2885,7 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) { reply_mix(CMD_ACK, isOK, 0, 0, buf, sizeof(buf)); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + iso14443a_off(); set_tracing(false); } @@ -3094,7 +3124,6 @@ void DetectNACKbug() { //reply_mix(CMD_ACK, isOK, num_nacks, i, 0, 0); BigBuf_free(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + iso14443a_off(); set_tracing(false); } diff --git a/bootrom/bootrom.c b/bootrom/bootrom.c index 4e92bc95b..0726f332d 100644 --- a/bootrom/bootrom.c +++ b/bootrom/bootrom.c @@ -153,11 +153,19 @@ void UsbPacketReceived(uint8_t *packet, int len) { case CMD_FINISH_WRITE: { uint32_t *flash_mem = (uint32_t *)(&_flash_start); for (int j = 0; j < 2; j++) { - for (i = 0 + (64 * j); i < 64 + (64 * j); i++) { - flash_mem[i] = c->d.asDwords[i]; - } - uint32_t flash_address = arg0 + (0x100 * j); + AT91PS_EFC efc_bank = AT91C_BASE_EFC0; + int offset = 0; + uint32_t page_n = (flash_address - ((uint32_t)flash_mem)) / AT91C_IFLASH_PAGE_SIZE; + if (page_n >= AT91C_IFLASH_NB_OF_PAGES / 2) { + page_n -= AT91C_IFLASH_NB_OF_PAGES / 2; + efc_bank = AT91C_BASE_EFC1; + // We need to offset the writes or it will not fill the correct bank write buffer. + offset = (AT91C_IFLASH_NB_OF_PAGES / 2) * AT91C_IFLASH_PAGE_SIZE / sizeof(uint32_t); + } + for (i = 0 + (64 * j); i < 64 + (64 * j); i++) { + flash_mem[offset + i] = c->d.asDwords[i]; + } /* Check that the address that we are supposed to write to is within our allowed region */ if (((flash_address + AT91C_IFLASH_PAGE_SIZE - 1) >= end_addr) || (flash_address < start_addr)) { @@ -165,16 +173,15 @@ void UsbPacketReceived(uint8_t *packet, int len) { dont_ack = 1; reply_old(CMD_NACK, 0, 0, 0, 0, 0); } else { - uint32_t page_n = (flash_address - ((uint32_t)flash_mem)) / AT91C_IFLASH_PAGE_SIZE; - /* Translate address to flash page and do flash, update here for the 512k part */ - AT91C_BASE_EFC0->EFC_FCR = MC_FLASH_COMMAND_KEY | - MC_FLASH_COMMAND_PAGEN(page_n) | - AT91C_MC_FCMD_START_PROG; + + efc_bank->EFC_FCR = MC_FLASH_COMMAND_KEY | + MC_FLASH_COMMAND_PAGEN(page_n) | + AT91C_MC_FCMD_START_PROG; } // Wait until flashing of page finishes uint32_t sr; - while (!((sr = AT91C_BASE_EFC0->EFC_FSR) & AT91C_MC_FRDY)); + while (!((sr = efc_bank->EFC_FSR) & AT91C_MC_FRDY)); if (sr & (AT91C_MC_LOCKE | AT91C_MC_PROGE)) { dont_ack = 1; reply_old(CMD_NACK, sr, 0, 0, 0, 0); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index a62924787..e75224cd2 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -3591,7 +3591,7 @@ static command_t CommandTable[] = { {"list", CmdHF14AMfList, AlwaysAvailable, "List Mifare history"}, {"darkside", CmdHF14AMfDarkside, IfPm3Iso14443a, "Darkside attack. read parity error messages."}, {"nested", CmdHF14AMfNested, IfPm3Iso14443a, "Nested attack. Test nested authentication"}, - {"hardnested", CmdHF14AMfNestedHard, IfPm3Iso14443a, "Nested attack for hardened Mifare cards"}, + {"hardnested", CmdHF14AMfNestedHard, AlwaysAvailable, "Nested attack for hardened Mifare cards"}, {"keybrute", CmdHF14AMfKeyBrute, IfPm3Iso14443a, "J_Run's 2nd phase of multiple sector nested authentication key recovery"}, {"nack", CmdHf14AMfNack, IfPm3Iso14443a, "Test for Mifare NACK bug"}, {"chk", CmdHF14AMfChk, IfPm3Iso14443a, "Check keys"}, diff --git a/client/default_keys.dic b/client/default_keys.dic index c8d96bd44..4df09cb1c 100644 --- a/client/default_keys.dic +++ b/client/default_keys.dic @@ -944,5 +944,9 @@ A23456789123 A00003000084 675A32413770 395244733978 +A0004A000036 +2C9F3D45BA13 +4243414F5250 +DFE73BE48AC6 # B069D0D03D17 diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 6657f2ce3..c814eb11e 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -539,7 +539,7 @@ int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, i--; } else { // (1) - card select error, (4) reply timeout, (200) - result length = 0 - if (res == 1 || res == 4 ||res == 200) { + if (res == 1 || res == 4 || res == 200) { if (!LeaveFieldON) DropFieldEx(channel); diff --git a/client/flash.c b/client/flash.c index e41b47fb0..abd81a9de 100644 --- a/client/flash.c +++ b/client/flash.c @@ -12,13 +12,6 @@ #define FLASH_START 0x100000 -#ifdef HAS_512_FLASH -# define FLASH_SIZE (512*1024) -#else -# define FLASH_SIZE (256*1024) -#endif - -#define FLASH_END (FLASH_START + FLASH_SIZE) #define BOOTLOADER_SIZE 0x2000 #define BOOTLOADER_END (FLASH_START + BOOTLOADER_SIZE) @@ -33,7 +26,7 @@ static const uint8_t elf_ident[] = { // Turn PHDRs into flasher segments, checking for PHDR sanity and merging adjacent // unaligned segments if needed -static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, Elf32_Phdr *phdrs, uint16_t num_phdrs) { +static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, Elf32_Phdr *phdrs, uint16_t num_phdrs, uint32_t flash_end) { Elf32_Phdr *phdr = phdrs; flash_seg_t *seg; uint32_t last_end = 0; @@ -77,11 +70,11 @@ static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, Elf32_Phdr *phdrs, PrintAndLogEx(ERR, "Error: PHDRs not sorted or overlap"); return -1; } - if (paddr < FLASH_START || (paddr + filesz) > FLASH_END) { + if (paddr < FLASH_START || (paddr + filesz) > flash_end) { PrintAndLogEx(ERR, "Error: PHDR is not contained in Flash"); return -1; } - if (vaddr >= FLASH_START && vaddr < FLASH_END && (flags & PF_W)) { + if (vaddr >= FLASH_START && vaddr < flash_end && (flags & PF_W)) { PrintAndLogEx(ERR, "Error: Flash VMA segment is writable"); return -1; } @@ -153,7 +146,7 @@ static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, Elf32_Phdr *phdrs, } // Sanity check segments and check for bootloader writes -static int check_segs(flash_file_t *ctx, int can_write_bl) { +static int check_segs(flash_file_t *ctx, int can_write_bl, uint32_t flash_end) { for (int i = 0; i < ctx->num_segs; i++) { flash_seg_t *seg = &ctx->segments[i]; @@ -165,7 +158,7 @@ static int check_segs(flash_file_t *ctx, int can_write_bl) { PrintAndLogEx(ERR, "Error: Segment is outside of flash bounds"); return -1; } - if (seg->start + seg->length > FLASH_END) { + if (seg->start + seg->length > flash_end) { PrintAndLogEx(ERR, "Error: Segment is outside of flash bounds"); return -1; } @@ -182,11 +175,12 @@ static int check_segs(flash_file_t *ctx, int can_write_bl) { } // Load an ELF file and prepare it for flashing -int flash_load(flash_file_t *ctx, const char *name, int can_write_bl) { +int flash_load(flash_file_t *ctx, const char *name, int can_write_bl, int flash_size) { FILE *fd; Elf32_Ehdr ehdr; Elf32_Phdr *phdrs = NULL; uint16_t num_phdrs; + uint32_t flash_end = FLASH_START + flash_size; int res; fd = fopen(name, "rb"); @@ -239,10 +233,10 @@ int flash_load(flash_file_t *ctx, const char *name, int can_write_bl) { goto fail; } - res = build_segs_from_phdrs(ctx, fd, phdrs, num_phdrs); + res = build_segs_from_phdrs(ctx, fd, phdrs, num_phdrs, flash_end); if (res < 0) goto fail; - res = check_segs(ctx, can_write_bl); + res = check_segs(ctx, can_write_bl, flash_end); if (res < 0) goto fail; @@ -362,15 +356,22 @@ int flash_start_flashing(int enable_bl_writes, char *serial_port_name, uint32_t *chipinfo = resp.oldarg[0]; } + uint32_t flash_end = FLASH_START + AT91C_IFLASH_PAGE_SIZE * AT91C_IFLASH_NB_OF_PAGES / 2; + if (((*chipinfo & 0xF00) >> 8) > 9) { + flash_end = FLASH_START + AT91C_IFLASH_PAGE_SIZE * AT91C_IFLASH_NB_OF_PAGES; + } + + PrintAndLogEx(INFO, "End of flash: 0x%08x", flash_end); + if (state & DEVICE_INFO_FLAG_UNDERSTANDS_START_FLASH) { // This command is stupid. Why the heck does it care which area we're // flashing, as long as it's not the bootloader area? The mind boggles. PacketResponseNG resp; if (enable_bl_writes) { - SendCommandBL(CMD_START_FLASH, FLASH_START, FLASH_END, START_FLASH_MAGIC, NULL, 0); + SendCommandBL(CMD_START_FLASH, FLASH_START, flash_end, START_FLASH_MAGIC, NULL, 0); } else { - SendCommandBL(CMD_START_FLASH, BOOTLOADER_END, FLASH_END, 0, NULL, 0); + SendCommandBL(CMD_START_FLASH, BOOTLOADER_END, flash_end, 0, NULL, 0); } return wait_for_ack(&resp); } else { diff --git a/client/flash.h b/client/flash.h index 7140de673..cc0387bf3 100644 --- a/client/flash.h +++ b/client/flash.h @@ -37,7 +37,7 @@ typedef struct { flash_seg_t *segments; } flash_file_t; -int flash_load(flash_file_t *ctx, const char *name, int can_write_bl); +int flash_load(flash_file_t *ctx, const char *name, int can_write_bl, int flash_size); int flash_start_flashing(int enable_bl_writes, char *serial_port_name, uint32_t *chipid); int flash_write(flash_file_t *ctx); void flash_free(flash_file_t *ctx); diff --git a/client/flasher.c b/client/flasher.c index 94e2ef6ba..25585e7cd 100644 --- a/client/flasher.c +++ b/client/flasher.c @@ -21,17 +21,23 @@ #include "ui.h" #define MAX_FILES 4 +#define ONE_KB 1024 static void usage(char *argv0) { - PrintAndLogEx(NORMAL, "Usage: %s [-b] image.elf [image.elf...]\n", argv0); - PrintAndLogEx(NORMAL, "\t-b\tEnable flashing of bootloader area (DANGEROUS)\n"); - PrintAndLogEx(NORMAL, "\nExample:\n\n\t %s "SERIAL_PORT_EXAMPLE_H" armsrc/obj/fullimage.elf", argv0); + PrintAndLogEx(NORMAL, "Usage: %s [-b] image.elf [image.elf...]", argv0); + PrintAndLogEx(NORMAL, " %s -i\n", argv0); + PrintAndLogEx(NORMAL, "\t-b\tEnable flashing of bootloader area (DANGEROUS)"); + PrintAndLogEx(NORMAL, "\t-i\tProbe the connected Proxmark3 to retrieve its memory size"); + PrintAndLogEx(NORMAL, "\nExamples:\n\t %s "SERIAL_PORT_EXAMPLE_H" -i", argv0); + PrintAndLogEx(NORMAL, "\t %s "SERIAL_PORT_EXAMPLE_H" armsrc/obj/fullimage.elf", argv0); #ifdef __linux__ - PrintAndLogEx(NORMAL, "\nNote (Linux): if the flasher gets stuck in 'Waiting for Proxmark3 to reappear on ',"); - PrintAndLogEx(NORMAL, " you need to blacklist Proxmark3 for modem-manager - see wiki for more details:\n"); - PrintAndLogEx(NORMAL, " https://github.com/Proxmark/proxmark3/wiki/Gentoo Linux\n"); - PrintAndLogEx(NORMAL, " https://github.com/Proxmark/proxmark3/wiki/Ubuntu Linux\n"); - PrintAndLogEx(NORMAL, " https://github.com/Proxmark/proxmark3/wiki/OSX\n"); + PrintAndLogEx(NORMAL, "\nNote (Linux):\nif the flasher gets stuck in 'Waiting for Proxmark3 to reappear on ',"); + PrintAndLogEx(NORMAL, "you need to blacklist Proxmark3 for modem-manager - see documentation for more details:"); + PrintAndLogEx(NORMAL, "* https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md"); + PrintAndLogEx(NORMAL, "\nMore info on flashing procedure from the official Proxmark3 wiki:"); + PrintAndLogEx(NORMAL, "* https://github.com/Proxmark/proxmark3/wiki/Gentoo%%20Linux"); + PrintAndLogEx(NORMAL, "* https://github.com/Proxmark/proxmark3/wiki/Ubuntu%%20Linux"); + PrintAndLogEx(NORMAL, "* https://github.com/Proxmark/proxmark3/wiki/OSX\n"); #endif } @@ -75,8 +81,10 @@ int main(int argc, char **argv) { int can_write_bl = 0; int num_files = 0; int res; + int ret = 0; flash_file_t files[MAX_FILES]; - + char *filenames[MAX_FILES]; + bool info = false; memset(files, 0, sizeof(files)); session.supports_colors = false; @@ -97,16 +105,14 @@ int main(int argc, char **argv) { if (argv[i][0] == '-') { if (!strcmp(argv[i], "-b")) { can_write_bl = 1; + } else if (!strcmp(argv[i], "-i")) { + info = true; } else { usage(argv[0]); return -1; } } else { - res = flash_load(&files[num_files], argv[i], can_write_bl); - if (res < 0) - return -1; - - PrintAndLogEx(NORMAL, ""); + filenames[num_files] = argv[i]; num_files++; } } @@ -122,8 +128,10 @@ int main(int argc, char **argv) { uint32_t chipid = 0; res = flash_start_flashing(can_write_bl, serial_port_name, &chipid); - if (res < 0) - return -1; + if (res < 0) { + ret = -1; + goto finish; + } int mem_avail = chipid_to_mem_avail(chipid); if (mem_avail != 0) { @@ -132,24 +140,44 @@ int main(int argc, char **argv) { PrintAndLogEx(NORMAL, "Available memory on this board: "_RED_("UNKNOWN")"\n"); PrintAndLogEx(ERR, _RED_("Note: Your bootloader does not understand the new CHIP_INFO command")); PrintAndLogEx(ERR, _RED_("It is recommended that you update your bootloader") "\n"); + mem_avail = 256; //we default to a low value } + + if (info) + goto finish; + + for (int i = 0 ; i < num_files; ++i) { + res = flash_load(&files[i], filenames[i], can_write_bl, mem_avail * ONE_KB); + if (res < 0) { + ret = -1; + goto finish; + } + PrintAndLogEx(NORMAL, ""); + } + PrintAndLogEx(SUCCESS, "\n" _BLUE_("Flashing...")); -// TODO check if enough space on Pm3 mem to write the given files + for (int i = 0; i < num_files; i++) { res = flash_write(&files[i]); - if (res < 0) - return -1; + if (res < 0) { + ret = -1; + goto finish; + } flash_free(&files[i]); PrintAndLogEx(NORMAL, "\n"); } +finish: res = flash_stop_flashing(); if (res < 0) - return -1; + ret = -1; CloseProxmark(); - PrintAndLogEx(SUCCESS, _BLUE_("All done.")); - PrintAndLogEx(SUCCESS, "\nHave a nice day!"); - return 0; + if (ret == 0) + PrintAndLogEx(SUCCESS, _BLUE_("All done.")); + else + PrintAndLogEx(ERR, "Aborted on error."); + PrintAndLogEx(NORMAL, "\nHave a nice day!"); + return ret; } diff --git a/tools/analyzesize.py b/tools/analyzesize.py new file mode 100755 index 000000000..4a5211c67 --- /dev/null +++ b/tools/analyzesize.py @@ -0,0 +1,33 @@ +#! /usr/bin/python3 + +import json +import subprocess +import sys + +def print_increase(x, y, name): + if x > y: + print("{} increase by: {} (0x{:08X}) bytes ({}%)".format(name, x-y, x-y, (x-y)*100/y)) + else: + print("{} decrease by: {} (0x{:08X}) bytes ({}%)".format(name, y-x, y-x, (y-x)*100/x)) +dbname = "tools/data.json" +try: + db = json.load(open(dbname,"r")) +except FileNotFoundError: + db = dict() + +if len(sys.argv) < 3: + print("Usage: analazysize.py ") + exit(-1) +action, name = sys.argv[1:3] +currentdata = subprocess.run(["arm-none-eabi-size","armsrc/obj/fullimage.stage1.elf"], stdout=subprocess.PIPE).stdout +currentdata = currentdata.split(b"\n")[1].strip() +text,data,bss = [int(x) for x in currentdata.split(b"\t")[:3]] +if action.lower() == "add": + db[name] = [text, data, bss] + json.dump(db, open(dbname, "w")) +elif action.lower() == "diff": + text_ref, data_ref, bss_ref = db[name] + flash_ref = text_ref+data_ref + flash = text+data + print_increase(flash, flash_ref, "Flash") + print_increase(bss, bss_ref, "RAM")