/// <summary>
        /// Creates a key generator for the runtime module pointed to by the address/size.
        /// </summary>
        /// <param name="memoryService">memory service instance</param>
        /// <param name="config">Target configuration: Windows, Linux or OSX</param>
        /// <param name="moduleFilePath">module path</param>
        /// <param name="address">module base address</param>
        /// <param name="size">module size</param>
        /// <returns>KeyGenerator or null if error</returns>
        public static KeyGenerator GetKeyGenerator(this IMemoryService memoryService, OSPlatform config, string moduleFilePath, ulong address, ulong size)
        {
            Stream       stream    = memoryService.CreateMemoryStream(address, size);
            KeyGenerator generator = null;

            if (config == OSPlatform.Linux)
            {
                var elfFile = new ELFFile(new StreamAddressSpace(stream), 0, true);
                generator = new ELFFileKeyGenerator(Tracer.Instance, elfFile, moduleFilePath);
            }
            else if (config == OSPlatform.OSX)
            {
                var machOFile = new MachOFile(new StreamAddressSpace(stream), 0, true);
                generator = new MachOFileKeyGenerator(Tracer.Instance, machOFile, moduleFilePath);
            }
            else if (config == OSPlatform.Windows)
            {
                var peFile = new PEFile(new StreamAddressSpace(stream), true);
                generator = new PEFileKeyGenerator(Tracer.Instance, peFile, moduleFilePath);
            }
            else
            {
                Trace.TraceError("GetKeyGenerator: unsupported platform {0}", config);
            }
            return(generator);
        }
Esempio n. 2
0
        public string GetSymbolFileName()
        {
            if (InitializeValue(Flags.InitializeSymbolFileName))
            {
                if (Target.OperatingSystem == OSPlatform.Linux)
                {
                    try
                    {
                        Stream stream  = ModuleService.RawMemoryService.CreateMemoryStream();
                        var    elfFile = new ELFFile(new StreamAddressSpace(stream), ImageBase, true);
                        if (elfFile.IsValid())
                        {
                            ELFSection section = elfFile.FindSectionByName(".gnu_debuglink");
                            if (section != null)
                            {
                                _symbolFileName = section.Contents.Read <string>(0);
                            }
                        }
                    }
                    catch (Exception ex) when
                        (ex is InvalidVirtualAddressException ||
                        ex is ArgumentOutOfRangeException ||
                        ex is IndexOutOfRangeException ||
                        ex is BadInputFormatException)

                    {
                        Trace.TraceWarning("ELF .gnu_debuglink section in {0}: {1}", this, ex.Message);
                    }
                }
            }
            return(_symbolFileName);
        }
Esempio n. 3
0
        public void CheckIndexingInfo()
        {
            using (Stream libcoreclr = TestUtilities.OpenCompressedFile("TestBinaries/libcoreclr.so.gz"))
            {
                StreamAddressSpace dataSource = new StreamAddressSpace(libcoreclr);
                ELFFile            elf        = new ELFFile(dataSource);
                Assert.True(elf.IsValid());
                Assert.True(elf.Header.Type == ELFHeaderType.Shared);
                string buildId = TestUtilities.ToHexString(elf.BuildID);

                //this is the build id for libcoreclr.so from package:
                // https://dotnet.myget.org/feed/dotnet-core/package/nuget/runtime.ubuntu.14.04-x64.Microsoft.NETCore.Runtime.CoreCLR/2.0.0-preview3-25428-01
                Assert.Equal("ef8f58a0b402d11c68f78342ef4fcc7d23798d4c", buildId);
            }

            // 32 bit arm ELF binary
            using (Stream apphost = TestUtilities.OpenCompressedFile("TestBinaries/apphost.gz"))
            {
                StreamAddressSpace dataSource = new StreamAddressSpace(apphost);
                ELFFile            elf        = new ELFFile(dataSource);
                Assert.True(elf.IsValid());
                Assert.True(elf.Header.Type == ELFHeaderType.Executable);
                string buildId = TestUtilities.ToHexString(elf.BuildID);

                //this is the build id for apphost from package:
                // https://dotnet.myget.org/F/dotnet-core/symbols/runtime.linux-arm.Microsoft.NETCore.DotNetAppHost/2.1.0-preview2-25512-03
                Assert.Equal("316d55471a8d5ebd6f2cb0631f0020518ab13dc0", buildId);
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Returns the ELF module build id or the MachO module uuid
        /// </summary>
        /// <param name="address">module base address</param>
        /// <returns>build id or null</returns>
        internal byte[] GetBuildId(ulong address)
        {
            // This code is called by the image mapping memory service so it needs to use the
            // original or raw memory service to prevent recursion so it can't use the ELFFile
            // or MachOFile instance that is available from the IModule.Services provider.
            Stream stream = RawMemoryService.CreateMemoryStream();

            byte[] buildId = null;
            try
            {
                if (Target.OperatingSystem == OSPlatform.Linux)
                {
                    var elfFile = new ELFFile(new StreamAddressSpace(stream), address, true);
                    if (elfFile.IsValid())
                    {
                        buildId = elfFile.BuildID;
                    }
                }
                else if (Target.OperatingSystem == OSPlatform.OSX)
                {
                    var machOFile = new MachOFile(new StreamAddressSpace(stream), address, true);
                    if (machOFile.IsValid())
                    {
                        buildId = machOFile.Uuid;
                    }
                }
            }
            catch (Exception ex) when(ex is InvalidVirtualAddressException || ex is BadInputFormatException || ex is IOException)
            {
                Trace.TraceError($"GetBuildId: {address:X16} exception {ex.Message}");
            }
            return(buildId);
        }
Esempio n. 5
0
        private static bool TryGetElfIndex(Stream stream, out string uuid)
        {
            uuid = null;

            try
            {
                var elf = new ELFFile(new StreamAddressSpace(stream));

                if (!elf.Ident.IsIdentMagicValid.Check())
                {
                    return(false);
                }

                if (elf.BuildID == null || elf.BuildID.Length != 20)
                {
                    return(false);
                }

                uuid = string.Concat(elf.BuildID.Select(b => b.ToString("x2"))).ToLowerInvariant();

                return(true);
            }
            catch (InputParsingException)
            {
                return(false);
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Returns the ELF module build id or the MachO module uuid
        /// </summary>
        /// <param name="address">module base address</param>
        /// <param name="size">module size</param>
        /// <returns>build id or null</returns>
        internal byte[] GetBuildId(ulong address, ulong size)
        {
            Debug.Assert(size > 0);
            Stream stream = MemoryService.CreateMemoryStream(address, size);

            byte[] buildId = null;
            try
            {
                if (Target.OperatingSystem == OSPlatform.Linux)
                {
                    var elfFile = new ELFFile(new StreamAddressSpace(stream), 0, true);
                    if (elfFile.IsValid())
                    {
                        buildId = elfFile.BuildID;
                    }
                }
                else if (Target.OperatingSystem == OSPlatform.OSX)
                {
                    var machOFile = new MachOFile(new StreamAddressSpace(stream), 0, true);
                    if (machOFile.IsValid())
                    {
                        buildId = machOFile.Uuid;
                    }
                }
            }
            catch (Exception ex) when(ex is InvalidVirtualAddressException || ex is BadInputFormatException || ex is IOException)
            {
                Trace.TraceError($"GetBuildId: {address:X16} exception {ex.Message}");
            }
            return(buildId);
        }
Esempio n. 7
0
        public static List<ProgrammableRegion> BuildFLASHImages(string targetPath, Dictionary<string, string> bspDict, Dictionary<string, string> debugMethodConfig, LiveMemoryLineHandler lineHandler)
        {
            string bspPath = bspDict["SYS:BSP_ROOT"];
            string toolchainPath = bspDict["SYS:TOOLCHAIN_ROOT"];

            string freq, mode, size;
            debugMethodConfig.TryGetValue("com.sysprogs.esp8266.xt-ocd.flash_freq", out freq);
            debugMethodConfig.TryGetValue("com.sysprogs.esp8266.xt-ocd.flash_mode", out mode);
            debugMethodConfig.TryGetValue("com.sysprogs.esp8266.xt-ocd.flash_size", out size);

            string partitionTable, bootloader, txtAppOffset;
            bspDict.TryGetValue("com.sysprogs.esp32.partition_table_file", out partitionTable);
            bspDict.TryGetValue("com.sysprogs.esp32.bootloader_file", out bootloader);
            bspDict.TryGetValue("com.sysprogs.esp32.app_offset", out txtAppOffset);

            uint appOffset;
            if (txtAppOffset == null)
                appOffset = 0;
            else if (txtAppOffset.StartsWith("0x"))
                uint.TryParse(txtAppOffset.Substring(2), NumberStyles.HexNumber, null, out appOffset);
            else
                uint.TryParse(txtAppOffset, out appOffset);

            if (appOffset == 0)
                throw new Exception("Application FLASH offset not defined. Please check your settings.");

            partitionTable = VariableHelper.ExpandVariables(partitionTable, bspDict, debugMethodConfig);
            bootloader = VariableHelper.ExpandVariables(bootloader, bspDict, debugMethodConfig);

            if (!string.IsNullOrEmpty(partitionTable) && !Path.IsPathRooted(partitionTable))
                partitionTable = Path.Combine(bspDict["SYS:PROJECT_DIR"], partitionTable);
            if (!string.IsNullOrEmpty(bootloader) && !Path.IsPathRooted(bootloader))
                bootloader = Path.Combine(bspDict["SYS:PROJECT_DIR"], bootloader);

            if (string.IsNullOrEmpty(partitionTable) || !File.Exists(partitionTable))
                throw new Exception("Unspecified or missing partition table file: " + partitionTable);
            if (string.IsNullOrEmpty(bootloader) || !File.Exists(bootloader))
                throw new Exception("Unspecified or missing bootloader file: " + bootloader);

            List<ProgrammableRegion> regions = new List<ProgrammableRegion>();

            using (var elfFile = new ELFFile(targetPath))
            {
                string pathBase = Path.Combine(Path.GetDirectoryName(targetPath), Path.GetFileName(targetPath));

                var img = ESP8266BinaryImage.MakeESP32ImageFromELFFile(elfFile, new ESP8266BinaryImage.ParsedHeader(freq, mode, size));

                //Bootloader/partition table offsets are hardcoded in ESP-IDF
                regions.Add(new ProgrammableRegion { FileName = bootloader, Offset = 0x1000, Size = GetFileSize(bootloader) });
                regions.Add(new ProgrammableRegion { FileName = partitionTable, Offset = 0x8000, Size = GetFileSize(partitionTable) });

                string fn = pathBase + "-esp32.bin";
                using (var fs = new FileStream(fn, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
                {
                    img.Save(fs);
                    regions.Add(new ProgrammableRegion { FileName = fn, Offset = (int)appOffset, Size = (int)fs.Length });
                }
            }
            return regions;
        }
Esempio n. 8
0
        /// <summary>
        /// Get the version string from a Linux or MacOS image
        /// </summary>
        /// <param name="address">image base</param>
        /// <param name="size">image size</param>
        /// <returns>version string or null</returns>
        protected string GetVersionString(ulong address, ulong size)
        {
            Stream stream = MemoryService.CreateMemoryStream(address, size);

            try
            {
                if (Target.OperatingSystem == OSPlatform.Linux)
                {
                    var elfFile = new ELFFile(new StreamAddressSpace(stream), 0, true);
                    if (elfFile.IsValid())
                    {
                        foreach (ELFProgramHeader programHeader in elfFile.Segments.Select((segment) => segment.Header))
                        {
                            uint flags = MemoryService.PointerSize == 8 ? programHeader.Flags : programHeader.Flags32;
                            if (programHeader.Type == ELFProgramHeaderType.Load &&
                                (flags & (uint)ELFProgramHeaderAttributes.Writable) != 0)
                            {
                                ulong loadAddress = programHeader.VirtualAddress.Value;
                                long  loadSize    = (long)programHeader.VirtualSize;
                                if (SearchVersionString(address + loadAddress, loadSize, out string productVersion))
                                {
                                    return(productVersion);
                                }
                            }
                        }
                    }
                }
                else if (Target.OperatingSystem == OSPlatform.OSX)
                {
                    var machOFile = new MachOFile(new StreamAddressSpace(stream), 0, true);
                    if (machOFile.IsValid())
                    {
                        foreach (MachSegmentLoadCommand loadCommand in machOFile.Segments.Select((segment) => segment.LoadCommand))
                        {
                            if (loadCommand.Command == LoadCommandType.Segment64 &&
                                (loadCommand.InitProt & VmProtWrite) != 0 &&
                                loadCommand.SegName.ToString() != "__LINKEDIT")
                            {
                                ulong loadAddress = loadCommand.VMAddress;
                                long  loadSize    = (long)loadCommand.VMSize;
                                if (SearchVersionString(address + loadAddress, loadSize, out string productVersion))
                                {
                                    return(productVersion);
                                }
                            }
                        }
                    }
                }
                else
                {
                    Trace.TraceError("GetVersionString: unsupported platform {0}", Target.OperatingSystem);
                }
            }
            catch (Exception ex) when(ex is InvalidVirtualAddressException || ex is BadInputFormatException || ex is IOException)
            {
                Trace.TraceError($"GetVersionString: {address:X16} exception {ex.Message}");
            }
            return(null);
        }
        /// <summary>
        /// Finds or downloads the ELF module and creates a ELFFile instance for it.
        /// </summary>
        /// <param name="module">module instance</param>
        /// <returns>ELFFile instance or null</returns>
        internal ELFFile GetELFFile(IModule module)
        {
            string  downloadFilePath = null;
            ELFFile elfFile          = null;

            if (File.Exists(module.FileName))
            {
                // TODO - Need to verify the build id matches this local file
                downloadFilePath = module.FileName;
            }
            else
            {
                if (SymbolService.IsSymbolStoreEnabled)
                {
                    if (!module.BuildId.IsDefaultOrEmpty)
                    {
                        var key = ELFFileKeyGenerator.GetKeys(KeyTypeFlags.IdentityKey, module.FileName, module.BuildId.ToArray(), symbolFile: false, symbolFileName: null).SingleOrDefault();
                        if (key != null)
                        {
                            // Now download the module from the symbol server
                            downloadFilePath = SymbolService.DownloadFile(key);
                        }
                    }
                }
            }

            if (!string.IsNullOrEmpty(downloadFilePath))
            {
                Trace.TraceInformation("GetELFFile: downloaded {0}", downloadFilePath);
                Stream stream;
                try
                {
                    stream = File.OpenRead(downloadFilePath);
                }
                catch (Exception ex) when(ex is DirectoryNotFoundException || ex is FileNotFoundException || ex is UnauthorizedAccessException || ex is IOException)
                {
                    Trace.TraceError($"GetELFFile: OpenRead exception {ex.Message}");
                    return(null);
                }
                try
                {
                    elfFile = new ELFFile(new StreamAddressSpace(stream), position: 0, isDataSourceVirtualAddressSpace: false);
                    if (!elfFile.IsValid())
                    {
                        return(null);
                    }
                }
                catch (Exception ex) when(ex is InvalidVirtualAddressException || ex is BadInputFormatException || ex is IOException)
                {
                    Trace.TraceError($"GetELFFile: exception {ex.Message}");
                    return(null);
                }
            }

            return(elfFile);
        }
Esempio n. 10
0
 /// <summary>
 /// Get the version string from a Linux or MacOS image
 /// </summary>
 /// <param name="module">module to get version string</param>
 /// <returns>version string or null</returns>
 protected string GetVersionString(IModule module)
 {
     try
     {
         ELFFile elfFile = module.Services.GetService <ELFFile>();
         if (elfFile is not null)
         {
             foreach (ELFProgramHeader programHeader in elfFile.Segments.Select((segment) => segment.Header))
             {
                 uint flags = MemoryService.PointerSize == 8 ? programHeader.Flags : programHeader.Flags32;
                 if (programHeader.Type == ELFProgramHeaderType.Load &&
                     (flags & (uint)ELFProgramHeaderAttributes.Writable) != 0)
                 {
                     ulong loadAddress = programHeader.VirtualAddress.Value;
                     long  loadSize    = (long)programHeader.VirtualSize;
                     if (SearchVersionString(module.ImageBase + loadAddress, loadSize, out string productVersion))
                     {
                         return(productVersion);
                     }
                 }
             }
             Trace.TraceInformation($"GetVersionString: not found in ELF file {module}");
         }
         else
         {
             MachOFile machOFile = module.Services.GetService <MachOFile>();
             if (machOFile is not null)
             {
                 foreach (MachSegmentLoadCommand loadCommand in machOFile.Segments.Select((segment) => segment.LoadCommand))
                 {
                     if (loadCommand.Command == LoadCommandType.Segment64 &&
                         (loadCommand.InitProt & VmProtWrite) != 0 &&
                         loadCommand.SegName.ToString() != "__LINKEDIT")
                     {
                         ulong loadAddress = loadCommand.VMAddress + machOFile.PreferredVMBaseAddress;
                         long  loadSize    = (long)loadCommand.VMSize;
                         if (SearchVersionString(loadAddress, loadSize, out string productVersion))
                         {
                             return(productVersion);
                         }
                     }
                 }
                 Trace.TraceInformation($"GetVersionString: not found in MachO file {module}");
             }
             else
             {
                 Trace.TraceError($"GetVersionString: unsupported module {module} or platform {Target.OperatingSystem}");
             }
         }
     }
     catch (Exception ex) when(ex is InvalidVirtualAddressException || ex is BadInputFormatException || ex is IOException)
     {
         Trace.TraceError($"GetVersionString: {module} exception {ex.Message}");
     }
     return(null);
 }
Esempio n. 11
0
        /// <summary>
        /// Load native symbols and modules (i.e. dac, dbi).
        /// </summary>
        /// <param name="callback">called back for each symbol file loaded</param>
        /// <param name="parameter">callback parameter</param>
        /// <param name="tempDirectory">temp directory unique to this instance of SOS</param>
        /// <param name="moduleFilePath">module path</param>
        /// <param name="address">module base address</param>
        /// <param name="size">module size</param>
        /// <param name="readMemory">read memory callback delegate</param>
        public static void LoadNativeSymbols(SymbolFileCallback callback, IntPtr parameter, string tempDirectory, string moduleFilePath, ulong address, int size, ReadMemoryDelegate readMemory)
        {
            if (IsSymbolStoreEnabled())
            {
                Debug.Assert(s_tracer != null);
                Stream       stream    = new TargetStream(address, size, readMemory);
                KeyTypeFlags flags     = KeyTypeFlags.SymbolKey | KeyTypeFlags.ClrKeys;
                KeyGenerator generator = null;

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                {
                    var elfFile = new ELFFile(new StreamAddressSpace(stream), 0, true);
                    generator = new ELFFileKeyGenerator(s_tracer, elfFile, moduleFilePath);
                }
                else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                {
                    var machOFile = new MachOFile(new StreamAddressSpace(stream), 0, true);
                    generator = new MachOFileKeyGenerator(s_tracer, machOFile, moduleFilePath);
                }
                else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    var peFile = new PEFile(new StreamAddressSpace(stream), true);
                    generator = new PEFileKeyGenerator(s_tracer, peFile, moduleFilePath);
                }
                else
                {
                    return;
                }

                try
                {
                    IEnumerable <SymbolStoreKey> keys = generator.GetKeys(flags);
                    foreach (SymbolStoreKey key in keys)
                    {
                        string moduleFileName = Path.GetFileName(key.FullPathName);
                        s_tracer.Verbose("{0} {1}", key.FullPathName, key.Index);

                        // Don't download the sos binaries that come with the runtime
                        if (moduleFileName != "SOS.NETCore.dll" && !moduleFileName.StartsWith("libsos."))
                        {
                            string downloadFilePath = GetSymbolFile(key, tempDirectory);
                            if (downloadFilePath != null)
                            {
                                s_tracer.Information("{0}: {1}", moduleFileName, downloadFilePath);
                                callback(parameter, moduleFileName, downloadFilePath);
                            }
                        }
                    }
                }
                catch (Exception ex) when(ex is BadInputFormatException || ex is InvalidVirtualAddressException)
                {
                    s_tracer.Error("{0}/{1:X16}: {2}", moduleFilePath, address, ex.Message);
                }
            }
        }
Esempio n. 12
0
    public static int Main(string[] args)
    {
        if (args.Length < 2 || string.IsNullOrEmpty(args[0]) || string.IsNullOrEmpty(args[1]))
        {
            throw new ArgumentException("Invalid command line arguments");
        }
        string moduleFileName = args[0];
        string outputFileName = args[1];

        using (FileStream stream = File.OpenRead(moduleFileName))
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                var    elfFile = new ELFFile(new StreamAddressSpace(stream));
                byte[] buildId = elfFile.BuildID;
                if (buildId != null)
                {
                    // First byte is the number of bytes total in the build id
                    string outputText = string.Format("0x{0:x2}, {1}", buildId.Length, ToHexString(buildId));
                    File.WriteAllText(outputFileName, outputText);
                }
                else
                {
                    throw new BadInputFormatException($"{moduleFileName} does not have a build id");
                }
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                var peFile = new PEFile(new StreamAddressSpace(stream));
                // First byte is the number of bytes total in the index
                string outputText = string.Format("0x{0:x2}, {1} {2}", 8, ToHexString(peFile.Timestamp), ToHexString(peFile.SizeOfImage));
                File.WriteAllText(outputFileName, outputText);
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                var    machoFile = new MachOFile(new StreamAddressSpace(stream));
                byte[] uuid      = machoFile.Uuid;
                if (uuid != null)
                {
                    // First byte is the number of bytes total in the build id
                    string outputText = string.Format("0x{0:x2}, {1}", uuid.Length, ToHexString(uuid));
                    File.WriteAllText(outputFileName, outputText);
                }
                else
                {
                    throw new BadInputFormatException($"{moduleFileName} does not have a uuid");
                }
            }
            else
            {
                throw new PlatformNotSupportedException(RuntimeInformation.OSDescription);
            }
        }
        return(0);
    }
Esempio n. 13
0
 public void CheckFreeBSDIndexingInfo()
 {
     using (Stream stream = File.OpenRead("TestBinaries/ilasm.dbg"))
     {
         StreamAddressSpace dataSource = new StreamAddressSpace(stream);
         ELFFile            elf        = new ELFFile(dataSource);
         Assert.True(elf.IsValid());
         Assert.True(elf.Header.Type == ELFHeaderType.Executable);
         string buildId = TestUtilities.ToHexString(elf.BuildID);
         Assert.Equal("4a91e41002a1307ef4097419d7875df001969daa", buildId);
     }
 }
Esempio n. 14
0
 public void CheckDbgIndexingInfo()
 {
     using (Stream stream = TestUtilities.OpenCompressedFile("TestBinaries/libcoreclrtraceptprovider.so.dbg.gz"))
     {
         StreamAddressSpace dataSource = new StreamAddressSpace(stream);
         ELFFile            elf        = new ELFFile(dataSource);
         Assert.True(elf.IsValid());
         Assert.True(elf.Header.Type == ELFHeaderType.Shared);
         string buildId = TestUtilities.ToHexString(elf.BuildID);
         Assert.Equal("ce4ce0558d878a05754dff246ccea2a70a1db3a8", buildId);
     }
 }
Esempio n. 15
0
 public void CheckCustomNamedBuildIdSection()
 {
     using (Stream stream = File.OpenRead("TestBinaries/renamed_build_id_section"))
     {
         StreamAddressSpace dataSource = new StreamAddressSpace(stream);
         ELFFile            elf        = new ELFFile(dataSource);
         Assert.True(elf.IsValid());
         Assert.True(elf.Header.Type == ELFHeaderType.Shared);
         string buildId = TestUtilities.ToHexString(elf.BuildID);
         Assert.Equal("1bd6a199dcb6f234558d9439cfcbba2727f1e1d9", buildId);
     }
 }
Esempio n. 16
0
        public Module(ITarget target)
        {
            ServiceProvider = new ServiceProvider();
            ServiceProvider.AddServiceFactoryWithNoCaching <PEFile>(() => GetPEInfo());
            ServiceProvider.AddService <IExportSymbols>(this);

            ServiceProvider.AddServiceFactory <PEReader>(() => {
                if (!IndexTimeStamp.HasValue || !IndexFileSize.HasValue)
                {
                    return(null);
                }
                return(Utilities.OpenPEReader(ModuleService.SymbolService.DownloadModuleFile(this)));
            });

            if (target.OperatingSystem == OSPlatform.Linux)
            {
                ServiceProvider.AddServiceFactory <ELFModule>(() => {
                    if (BuildId.IsDefaultOrEmpty)
                    {
                        return(null);
                    }
                    return(ELFModule.OpenFile(ModuleService.SymbolService.DownloadModuleFile(this)));
                });
                ServiceProvider.AddServiceFactory <ELFFile>(() => {
                    Stream stream = ModuleService.MemoryService.CreateMemoryStream();
                    var elfFile   = new ELFFile(new StreamAddressSpace(stream), ImageBase, true);
                    return(elfFile.IsValid() ? elfFile : null);
                });
            }

            if (target.OperatingSystem == OSPlatform.OSX)
            {
                ServiceProvider.AddServiceFactory <MachOModule>(() => {
                    if (BuildId.IsDefaultOrEmpty)
                    {
                        return(null);
                    }
                    return(MachOModule.OpenFile(ModuleService.SymbolService.DownloadModuleFile(this)));
                });
                ServiceProvider.AddServiceFactory <MachOFile>(() => {
                    Stream stream = ModuleService.MemoryService.CreateMemoryStream();
                    var machoFile = new MachOFile(new StreamAddressSpace(stream), ImageBase, true);
                    return(machoFile.IsValid() ? machoFile : null);
                });
            }

            _onChangeEvent = target.Services.GetService <ISymbolService>()?.OnChangeEvent.Register(() => {
                ServiceProvider.RemoveService(typeof(MachOModule));
                ServiceProvider.RemoveService(typeof(ELFModule));
                ServiceProvider.RemoveService(typeof(PEReader));
            });
        }
Esempio n. 17
0
        public void CheckIndexingInfo()
        {
            using (FileStream libcoreclr = File.OpenRead("TestBinaries\\libcoreclr.so"))
            {
                StreamAddressSpace dataSource = new StreamAddressSpace(libcoreclr);
                ELFFile            elf        = new ELFFile(dataSource);
                string             buildId    = string.Concat(elf.BuildID.Select(b => b.ToString("x2")));

                //this is the build id for libcoreclr.so from package:
                // https://dotnet.myget.org/feed/dotnet-core/package/nuget/runtime.ubuntu.14.04-x64.Microsoft.NETCore.Runtime.CoreCLR/1.0.2
                Assert.Equal("bc0d85e535168f1a21a2dd79a466b3988bd274aa", buildId);
            }
        }
Esempio n. 18
0
        public static ELFProcess LoadProcess_FromELFExe(File ELFExeFile, bool UserMode)
        {
            //bool reenable = Scheduler.Enabled;
            //if (reenable)
            //{
            //    Scheduler.Disable();
            //}
            ELFProcess result = new ELFFile(ELFExeFile).LoadExecutable(UserMode);

            //if (reenable)
            //{
            //    Scheduler.Enable();
            //}
            return(result);
        }
Esempio n. 19
0
        public static ELFSharedObject LoadLibrary_FromELFSO(File ELFSharedObjectFile, ELFProcess theProcess)
        {
            //bool reenable = Scheduler.Enabled;
            //if (reenable)
            //{
            //    Scheduler.Disable();
            //}
            ELFSharedObject result = new ELFFile(ELFSharedObjectFile).LoadSharedObject(theProcess);

            //if (reenable)
            //{
            //    Scheduler.Enable();
            //}
            return(result);
        }
Esempio n. 20
0
 void DisplaySegments(ulong address)
 {
     try
     {
         if (Target.OperatingSystem == OSPlatform.Linux)
         {
             Stream stream  = MemoryService.CreateMemoryStream();
             var    elfFile = new ELFFile(new StreamAddressSpace(stream), address, true);
             if (elfFile.IsValid())
             {
                 foreach (ELFProgramHeader programHeader in elfFile.Segments.Select((segment) => segment.Header))
                 {
                     uint   flags       = MemoryService.PointerSize == 8 ? programHeader.Flags : programHeader.Flags32;
                     ulong  loadAddress = programHeader.VirtualAddress;
                     ulong  loadSize    = programHeader.VirtualSize;
                     ulong  fileOffset  = programHeader.FileOffset;
                     string type        = programHeader.Type.ToString();
                     WriteLine($"        Segment: {loadAddress:X16} {loadSize:X16} {fileOffset:X16} {flags:x2} {type}");
                 }
             }
         }
         else if (Target.OperatingSystem == OSPlatform.OSX)
         {
             Stream    stream    = MemoryService.CreateMemoryStream();
             MachOFile machOFile = new(new StreamAddressSpace(stream), address, true);
             if (machOFile.IsValid())
             {
                 WriteLine("    LoadAddress:     {0:X16}", machOFile.LoadAddress);
                 WriteLine("    LoadBias:        {0:X16}", machOFile.PreferredVMBaseAddress);
                 for (int i = 0; i < machOFile.Segments.Length; i++)
                 {
                     MachSegment segment     = machOFile.Segments[i];
                     ulong       loadAddress = segment.LoadCommand.VMAddress;
                     ulong       loadSize    = segment.LoadCommand.VMSize;
                     ulong       fileOffset  = segment.LoadCommand.FileOffset;
                     uint        prot        = segment.LoadCommand.InitProt;
                     string      name        = segment.LoadCommand.SegName.ToString();
                     WriteLine($"        Segment {i}: {loadAddress:X16} {loadSize:X16} {fileOffset:X16} {prot:x2} {name}");
                 }
             }
         }
     }
     catch (Exception ex) when(ex is InvalidVirtualAddressException || ex is BadInputFormatException)
     {
         Trace.TraceError($"Exception displaying module segments: {ex}");
     }
 }
Esempio n. 21
0
        /// <summary>
        /// Finds or downloads the ELF module and creates a ELFFile instance for it.
        /// </summary>
        /// <param name="module">module instance</param>
        /// <returns>ELFFile instance or null</returns>
        internal ELFFile GetELFFile(IModule module)
        {
            if (module.BuildId.IsDefaultOrEmpty)
            {
                Trace.TraceWarning($"GetELFFile: module {module.FileName} has no build id");
                return(null);
            }

            SymbolStoreKey moduleKey = ELFFileKeyGenerator.GetKeys(KeyTypeFlags.IdentityKey, module.FileName, module.BuildId.ToArray(), symbolFile: false, symbolFileName: null).SingleOrDefault();

            if (moduleKey is null)
            {
                Trace.TraceWarning($"GetELFFile: no index generated for module {module.FileName} ");
                return(null);
            }

            if (File.Exists(module.FileName))
            {
                ELFFile elfFile = OpenELFFile(module.FileName);
                if (elfFile is not null)
                {
                    var generator = new ELFFileKeyGenerator(Tracer.Instance, elfFile, module.FileName);
                    IEnumerable <SymbolStoreKey> keys = generator.GetKeys(KeyTypeFlags.IdentityKey);
                    foreach (SymbolStoreKey key in keys)
                    {
                        if (moduleKey.Equals(key))
                        {
                            Trace.TraceInformation("GetELFFile: local file match {0}", module.FileName);
                            return(elfFile);
                        }
                    }
                }
            }

            // Now download the module from the symbol server if local file doesn't exists or doesn't have the right key
            string downloadFilePath = SymbolService.DownloadFile(moduleKey);

            if (!string.IsNullOrEmpty(downloadFilePath))
            {
                Trace.TraceInformation("GetELFFile: downloaded {0}", downloadFilePath);
                return(OpenELFFile(downloadFilePath));
            }

            return(null);
        }
Esempio n. 22
0
 void DisplaySegments(IModule module)
 {
     try
     {
         ELFFile elfFile = module.Services.GetService <ELFFile>();
         if (elfFile is not null)
         {
             foreach (ELFProgramHeader programHeader in elfFile.Segments.Select((segment) => segment.Header))
             {
                 uint   flags       = MemoryService.PointerSize == 8 ? programHeader.Flags : programHeader.Flags32;
                 ulong  loadAddress = programHeader.VirtualAddress;
                 ulong  loadSize    = programHeader.VirtualSize;
                 ulong  fileOffset  = programHeader.FileOffset;
                 string type        = programHeader.Type.ToString();
                 WriteLine($"        Segment: {loadAddress:X16} {loadSize:X16} {fileOffset:X16} {flags:x2} {type}");
             }
         }
         else
         {
             MachOFile machOFile = module.Services.GetService <MachOFile>();
             if (machOFile is not null)
             {
                 WriteLine("    LoadAddress:     {0:X16}", machOFile.LoadAddress);
                 WriteLine("    LoadBias:        {0:X16}", machOFile.PreferredVMBaseAddress);
                 for (int i = 0; i < machOFile.Segments.Length; i++)
                 {
                     MachSegment segment     = machOFile.Segments[i];
                     ulong       loadAddress = segment.LoadCommand.VMAddress;
                     ulong       loadSize    = segment.LoadCommand.VMSize;
                     ulong       fileOffset  = segment.LoadCommand.FileOffset;
                     uint        prot        = segment.LoadCommand.InitProt;
                     string      name        = segment.LoadCommand.SegName.ToString();
                     WriteLine($"        Segment {i}: {loadAddress:X16} {loadSize:X16} {fileOffset:X16} {prot:x2} {name}");
                 }
             }
         }
     }
     catch (Exception ex) when(ex is InvalidVirtualAddressException || ex is BadInputFormatException)
     {
         Trace.TraceError($"Exception displaying module segments: {ex}");
     }
 }
Esempio n. 23
0
        public string ComputeIndexKey(string path, Stream fileStream)
        {
            try
            {
                string extension = Path.GetExtension(path);
                if (!string.IsNullOrEmpty(extension) && extension != ".so" && extension != ".dbg")
                {
                    return(null);
                }
                ELFFile elf = new ELFFile(new StreamAddressSpace(fileStream));
                if (!elf.Ident.IsIdentMagicValid.Check())
                {
                    return(null);
                }
                if (elf.BuildID == null || elf.BuildID.Length != 20)
                {
                    Console.WriteLine("WARNING: ELF file is missing build id - " + path);
                    return(null);
                }

                string        filename = Path.GetFileName(path).ToLowerInvariant();
                StringBuilder key      = new StringBuilder();
                key.Append(filename);
                key.Append("/elf-buildid-");
                //TODO: it would be nice to check if the file is really stripped rather than blindly
                //trusting the file extension
                bool isStripped = extension != ".dbg";
                key.Append(isStripped ? "" : "sym-");
                key.Append(string.Concat(elf.BuildID.Select(b => b.ToString("x2"))).ToLowerInvariant());
                key.Append("/");
                key.Append(filename);
                return(key.ToString());
            }
            catch (InputParsingException)
            {
                return(null);
            }
        }
Esempio n. 24
0
        /// <summary>
        /// Opens and returns an ELFFile instance from the local file path
        /// </summary>
        /// <param name="filePath">ELF file to open</param>
        /// <returns>ELFFile instance or null</returns>
        private ELFFile OpenELFFile(string filePath)
        {
            Stream stream = OpenFile(filePath);

            if (stream is not null)
            {
                try
                {
                    ELFFile elfFile = new ELFFile(new StreamAddressSpace(stream), position: 0, isDataSourceVirtualAddressSpace: false);
                    if (!elfFile.IsValid())
                    {
                        Trace.TraceError($"OpenELFFile: not a valid file");
                        return(null);
                    }
                    return(elfFile);
                }
                catch (Exception ex) when(ex is InvalidVirtualAddressException || ex is BadInputFormatException || ex is IOException)
                {
                    Trace.TraceError($"OpenELFFile: exception {ex.Message}");
                }
            }
            return(null);
        }
            public CustomStartupSequence BuildSequence(string targetPath, Dictionary<string, string> bspDict, Dictionary<string, string> debugMethodConfig, LiveMemoryLineHandler lineHandler)
            {
                if (!File.Exists(targetPath))
                    throw new Exception(targetPath + " not found. Debugging will not be possible.");

                bool stubFound = false;
                using (var elf = new ELFFile(targetPath))
                {
                    foreach (var sym in elf.LoadAllSymbols())
                    {
                        if (sym.Name == "gdbstub_init")
                        {
                            stubFound = true;
                            break;
                        }
                    }
                }

                if (!stubFound)
                {
                    var wrp = new ResultWrapper();
                    _SyncContext.Send(o => ((ResultWrapper)o).Result = MessageBox.Show("The programmed image does not contain the GDB stub. Do you want to open instructions on debugging with ESP8266 GDB stub?", "VisualGDB", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information), wrp);
                    switch(wrp.Result)
                    {
                        case DialogResult.Yes:
                            Process.Start("http://visualgdb.com/KB/esp8266gdbstub");
                            goto case DialogResult.Cancel;
                        case DialogResult.No:
                            break;
                        case DialogResult.Cancel:
                            throw new OperationCanceledException();
                    }
                }

                string val;
                if (!debugMethodConfig.TryGetValue("com.sysprogs.esp8266.program_flash", out val) || val != "0")
                {
                    var wrp = new ResultWrapper();
                    _SyncContext.Send(o => ((ResultWrapper)o).Result = MessageBox.Show("Please reboot your ESP8266 into the bootloader mode and press OK.", "VisualGDB", MessageBoxButtons.OKCancel, MessageBoxIcon.Information), wrp);
                    if (wrp.Result != DialogResult.OK)
                        throw new OperationCanceledException();

                    using (var serialPort = new SerialPortStream(debugMethodConfig["com.sysprogs.esp8266.gdbstub.com_port"], int.Parse(debugMethodConfig["com.sysprogs.esp8266.gdbstub.bl_baud"]), System.IO.Ports.Handshake.None))
                    {
                        serialPort.AllowTimingOutWithZeroBytes = true;
                        int resetDelay;
                        if (!debugMethodConfig.TryGetValue("com.sysprogs.esp8266.reset_delay", out val) || !int.TryParse(val, out resetDelay))
                            resetDelay = 25;

                        string seq;
                        debugMethodConfig.TryGetValue("com.sysprogs.esp8266.gdbstub.reset_sequence", out seq);
                        ESP8266BootloaderClient client = new ESP8266BootloaderClient(serialPort, resetDelay, seq);
                        client.Sync();
                        var regions = ESP8266StartupSequence.BuildFLASHImages(targetPath, bspDict, debugMethodConfig, lineHandler);

                        ProgramProgressForm frm = null;
                        _SyncContext.Post(o => { frm = new ProgramProgressForm(); frm.ShowDialog(); }, null);
                        int totalSize = 0;
                        foreach (var r in regions)
                            totalSize += r.Size;

                        ESP8266BootloaderClient.BlockWrittenHandler handler = (s, a, len) => frm.UpdateProgressAndThrowIfCanceled(a, len, totalSize);
                        bool useDIO = false;

                        try
                        {
                            client.BlockWritten += handler;
                            foreach (var r in regions)
                            {
                                var data = File.ReadAllBytes(r.FileName);
                                if (r.Offset == 0 && data.Length >= 4)
                                    useDIO = (data[2] == 2);

                                client.ProgramFLASH((uint)r.Offset, data);
                            }
                        }
                        finally
                        {
                            client.BlockWritten -= handler;
                            _SyncContext.Post(o => { frm.Close(); frm.Dispose(); }, null);
                        }

                        client.RunProgram(useDIO, false);
                    }
                }

                string tmp = null;
                if (debugMethodConfig?.TryGetValue("SYS:PROGRAM_WITHOUT_DEBUGGING", out tmp) == true && tmp == "1")
                    return null;    //Suppress connecting to gdb

                return new CustomStartupSequence
                {
                    Steps = new List<CustomStartStep> {
                        new CustomStartStep("set serial baud $$com.sysprogs.esp8266.gdbstub.baud$$"),
                        new CustomStartStep(@"target remote \\.\$$com.sysprogs.esp8266.gdbstub.com_port$$"),
                    }
                };
            }
Esempio n. 26
0
        static void Run(string[] args)
        {
            Console.WriteLine("ESP8266 image tool v1.0 [http://sysprogs.com/]");
            if (args.Length < 1)
            {
                PrintUsage();
                return;
            }

            string        port = null;
            string        bootloader = null;
            int           otaPort = 0;
            int           baud = 115200;
            bool          erase = false;
            bool          esp32mode = false;
            List <string> files = new List <string>();
            string        frequency = null, mode = null, size = null;

            for (int i = 0; i < args.Length; i++)
            {
                if (args[i] == "--esp32")
                {
                    esp32mode = true;
                }
                else if (args[i] == "--boot")
                {
                    if (i >= (args.Length - 1))
                    {
                        throw new Exception("--boot must be followed by the bootloader image");
                    }
                    bootloader = args[++i];
                }
                else if (args[i] == "--program")
                {
                    if (i >= (args.Length - 1))
                    {
                        throw new Exception("--program must be followed by port number");
                    }
                    port = args[++i];
                    if ((i + 1) < args.Length && !args[i + 1].StartsWith("-"))
                    {
                        baud = int.Parse(args[++i]);
                    }
                }
                else if (args[i] == "--mode")
                {
                    if (i >= (args.Length - 1))
                    {
                        throw new Exception("--mode must be followed by FLASH mode");
                    }
                    mode = args[++i];
                }
                else if (args[i] == "--size")
                {
                    if (i >= (args.Length - 1))
                    {
                        throw new Exception("--size must be followed by FLASH mode");
                    }
                    size = args[++i];
                }
                else if (args[i] == "--freq")
                {
                    if (i >= (args.Length - 1))
                    {
                        throw new Exception("--freq must be followed by FLASH mode");
                    }
                    frequency = args[++i];
                }
                else if (args[i].ToLower() == "--ota")
                {
                    if (i >= (args.Length - 1))
                    {
                        throw new Exception("--OTA must be followed by port number");
                    }
                    otaPort = int.Parse(args[++i]);
                }
                else if (args[i] == "--erase")
                {
                    erase = true;
                }
                else
                {
                    files.Add(args[i]);
                }
            }

            ESP8266BinaryImage.ParsedHeader hdr = new ESP8266BinaryImage.ParsedHeader(frequency, mode, size);
            Console.WriteLine("FLASH Parameters:");
            Console.WriteLine("\tFrequency: " + DumpEnumValue(hdr.Frequency));
            Console.WriteLine("\tMode: " + DumpEnumValue(hdr.Mode));
            Console.WriteLine("\tSize: " + DumpEnumValue(hdr.Size));

            if (otaPort != 0)
            {
                OTAServer.ServeOTAFiles(otaPort, hdr, files.ToArray());
                return;
            }

            foreach (var elf in files)
            {
                string pathBase = Path.ChangeExtension(elf, ".").TrimEnd('.');
                List <ProgrammableRegion> regions = new List <ProgrammableRegion>();

                Console.WriteLine("Processing " + elf + "...");

                using (var elfFile = new ELFFile(elf))
                {
                    string status;
                    if (esp32mode)
                    {
                        var img = ESP8266BinaryImage.MakeESP32ImageFromELFFile(elfFile, hdr);

                        string fn = pathBase + "-esp32.bin";
                        using (var fs = new FileStream(fn, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
                        {
                            img.Save(fs);
                            regions.Add(new ProgrammableRegion {
                                FileName = fn, Offset = 0, Size = (int)fs.Length
                            });
                        }
                    }
                    else
                    {
                        int appMode = ESP8266BinaryImage.DetectAppMode(elfFile, out status);
                        Console.WriteLine(status);

                        if (appMode == 0)
                        {
                            var img = ESP8266BinaryImage.MakeNonBootloaderImageFromELFFile(elfFile, hdr);

                            string fn = pathBase + "-0x00000.bin";
                            using (var fs = new FileStream(fn, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
                            {
                                img.Save(fs);
                                regions.Add(new ProgrammableRegion {
                                    FileName = fn, Offset = 0, Size = (int)fs.Length
                                });
                            }

                            foreach (var sec in ESP8266BinaryImage.GetFLASHSections(elfFile))
                            {
                                fn = string.Format("{0}-0x{1:x5}.bin", pathBase, sec.OffsetInFLASH);
                                using (var fs = new FileStream(fn, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
                                {
                                    fs.Write(sec.Data, 0, sec.Data.Length);
                                    regions.Add(new ProgrammableRegion {
                                        FileName = fn, Offset = (int)sec.OffsetInFLASH, Size = sec.Data.Length
                                    });
                                }
                            }
                        }
                        else
                        {
                            string fn;
                            var    img = ESP8266BinaryImage.MakeBootloaderBasedImageFromELFFile(elfFile, hdr, appMode);

                            if (bootloader == null)
                            {
                                Console.WriteLine("Warning: no bootloader specified. Skipping bootloader...");
                            }
                            else
                            {
                                if (!File.Exists(bootloader))
                                {
                                    throw new Exception(bootloader + " not found. Cannot program OTA images.");
                                }

                                byte[] data = File.ReadAllBytes(bootloader);
                                data[2] = (byte)img.Header.Mode;
                                data[3] = (byte)(((byte)img.Header.Size << 4) | (byte)img.Header.Frequency);
                                fn      = string.Format("{0}-boot.bin", pathBase);
                                File.WriteAllBytes(fn, data);

                                regions.Add(new ProgrammableRegion {
                                    FileName = fn, Offset = 0, Size = File.ReadAllBytes(fn).Length
                                });
                            }

                            fn = string.Format("{0}-user{1}.bin", pathBase, appMode);
                            using (var fs = new FileStream(fn, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
                            {
                                img.Save(fs);
                                regions.Add(new ProgrammableRegion {
                                    FileName = fn, Offset = (int)img.BootloaderImageOffset, Size = (int)fs.Length
                                });
                            }
                        }
                    }
                }

                if (port != null)
                {
                    using (var serialPort = new SerialPortStream(port, baud, System.IO.Ports.Handshake.None)
                    {
                        AllowTimingOutWithZeroBytes = true
                    })
                    {
                        ESP8266BootloaderClient client = new ESP8266BootloaderClient(serialPort, 50, null);
                        Console.WriteLine("Connecting to bootloader on {0}...", port);
                        client.Sync();
                        if (erase)
                        {
                            Console.WriteLine("Erasing FLASH...");
                            client.EraseFLASH();
                            Console.WriteLine("FLASH erased. Please restart your ESP8266 into the bootloader mode again.\r\nPress any key when done...");
                            Console.ReadKey();
                            client.Sync();
                        }
                        foreach (var region in regions)
                        {
                            DateTime start = DateTime.Now;
                            Console.WriteLine("Programming " + Path.GetFileName(region.FileName) + "...");
                            var tracker = new ProgressTracker(region);
                            client.BlockWritten += tracker.BlockWritten;
                            client.ProgramFLASH((uint)region.Offset, File.ReadAllBytes(region.FileName));
                            client.BlockWritten -= tracker.BlockWritten;
                            Console.WriteLine("\rProgrammed in {0} seconds        ", (int)(DateTime.Now - start).TotalSeconds);
                        }
                    }
                }
                else
                {
                    int fileNameLen = Path.GetFileName(args[0]).Length + 10;
                    Console.WriteLine("\r\nCreated the following files:");

                    Console.WriteLine("File".PadRight(fileNameLen) + " FLASH Offset  Size");
                    foreach (var region in regions)
                    {
                        Console.WriteLine(Path.GetFileName(region.FileName).PadRight(fileNameLen) + " " + string.Format("0x{0:x8}    {1}KB", region.Offset, region.Size / 1024));
                    }
                }
            }
        }
Esempio n. 27
0
        public static List<ProgrammableRegion> BuildFLASHImages(string targetPath, Dictionary<string, string> bspDict, Dictionary<string, string> debugMethodConfig, LiveMemoryLineHandler lineHandler)
        {
            string bspPath = bspDict["SYS:BSP_ROOT"];
            string toolchainPath = bspDict["SYS:TOOLCHAIN_ROOT"];

            Regex rgBinFile = new Regex("^" + Path.GetFileName(targetPath) + "-0x([0-9a-fA-F]+)\\.bin$", RegexOptions.IgnoreCase);
            foreach (var fn in Directory.GetFiles(Path.GetDirectoryName(targetPath)))
                if (rgBinFile.IsMatch(Path.GetFileName(fn)))
                    File.Delete(fn);

            string freq, mode, size;
            debugMethodConfig.TryGetValue("com.sysprogs.esp8266.xt-ocd.flash_freq", out freq);
            debugMethodConfig.TryGetValue("com.sysprogs.esp8266.xt-ocd.flash_mode", out mode);
            debugMethodConfig.TryGetValue("com.sysprogs.esp8266.xt-ocd.flash_size", out size);

            List<ProgrammableRegion> regions = new List<ProgrammableRegion>();

            using (var elfFile = new ELFFile(targetPath))
            {
                string pathBase = Path.Combine(Path.GetDirectoryName(targetPath), Path.GetFileName(targetPath));
                string status;
                int appMode = ESP8266BinaryImage.DetectAppMode(elfFile, out status);
                if (status != null && lineHandler != null)
                    lineHandler(status, true);

                if (appMode == 0)
                {
                    var img = ESP8266BinaryImage.MakeNonBootloaderImageFromELFFile(elfFile, new ESP8266BinaryImage.ParsedHeader(freq, mode, size));

                    string fn = pathBase + "-0x00000.bin";
                    using (var fs = new FileStream(fn, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
                    {
                        img.Save(fs);
                        regions.Add(new ProgrammableRegion { FileName = fn, Offset = 0, Size = (int)fs.Length });
                    }

                    foreach (var sec in ESP8266BinaryImage.GetFLASHSections(elfFile))
                    {
                        fn = string.Format("{0}-0x{1:x5}.bin", pathBase, sec.OffsetInFLASH);
                        using (var fs = new FileStream(fn, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
                        {
                            fs.Write(sec.Data, 0, sec.Data.Length);
                            regions.Add(new ProgrammableRegion { FileName = fn, Offset = (int)sec.OffsetInFLASH, Size = sec.Data.Length });
                        }
                    }
                }
                else
                {
                    var img = ESP8266BinaryImage.MakeBootloaderBasedImageFromELFFile(elfFile, new ESP8266BinaryImage.ParsedHeader(freq, mode, size), appMode);

                    string bspRoot, bootloader;
                    if (!bspDict.TryGetValue("SYS:BSP_ROOT", out bspRoot) || !bspDict.TryGetValue("com.sysprogs.esp8266.bootloader", out bootloader))
                        throw new Exception("Cannot determine bootloader image path. Please check your BSP consistency.");

                    string fn = Path.Combine(bspRoot, bootloader);
                    if (!File.Exists(fn))
                        throw new Exception(fn + " not found. Cannot program OTA images.");

                    byte[] data = File.ReadAllBytes(fn);
                    data[2] = (byte)img.Header.Mode;
                    data[3] = (byte)(((byte)img.Header.Size << 4) | (byte)img.Header.Frequency);
                    fn = string.Format("{0}-0x00000.bin", pathBase);
                    File.WriteAllBytes(fn, data);

                    regions.Add(new ProgrammableRegion { FileName = fn, Offset = 0, Size = File.ReadAllBytes(fn).Length });

                    fn = string.Format("{0}-0x{1:x5}.bin", pathBase, img.BootloaderImageOffset);
                    using (var fs = new FileStream(fn, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
                    {
                        img.Save(fs);
                        regions.Add(new ProgrammableRegion { FileName = fn, Offset = (int)img.BootloaderImageOffset, Size = (int)fs.Length });
                    }
                }
            }
            return regions;
        }
Esempio n. 28
0
        public CustomStartupSequence BuildSequence(string targetPath, Dictionary<string, string> bspDict, Dictionary<string, string> debugMethodConfig, LiveMemoryLineHandler lineHandler)
        {
            bool isOpenOCD = debugMethodConfig.ContainsKey("com.sysprogs.esp8266.openocd.iface_script");

            List<CustomStartStep> cmds = new List<CustomStartStep>();
            cmds.Add(new CustomStartStep(isOpenOCD ? "mon reset halt" : "maint packet R",
                "-exec-next-instruction",
                "set $com_sysprogs_esp8266_wdcfg=0",
                "set $vecbase=0x40000000",
                "$$com.sysprogs.esp8266.interrupt_disable_command$$",
                "set $ccompare=0",
                "set $intclear=-1",
                "set $intenable=0",
                "set $eps2=0x20",
                "set $icountlevel=0"));

            var result = new CustomStartupSequence { Steps = cmds };

            string val;
            if (bspDict.TryGetValue("com.sysprogs.esp8266.load_flash", out val) && val == "1")  //Not a FLASHless project
            {
                if (debugMethodConfig.TryGetValue("com.sysprogs.esp8266.xt-ocd.program_flash", out val) && val != "0")
                {
                    string bspPath = bspDict["SYS:BSP_ROOT"];
                    List<ProgrammableRegion> regions = BuildFLASHImages(targetPath, bspDict, debugMethodConfig, lineHandler);

                    string loader = bspPath + @"\sysprogs\flashprog\ESP8266FlashProg.bin";
                    if (!File.Exists(loader))
                        throw new Exception("FLASH loader not found: " + loader);

                    var parsedLoader = new ParsedFLASHLoader(loader);

                    cmds.Add(new CustomStartStep("print *((int *)0x60000900)", "set *((int *)0x60000900)=0"));
                    cmds.Add(parsedLoader.QueueInvocation(0, "$$com.sysprogs.esp8266.xt-ocd.prog_sector_size$$", "$$com.sysprogs.esp8266.xt-ocd.erase_sector_size$$", null, 0, 0, true));
                    foreach (var region in regions)
                        parsedLoader.QueueRegionProgramming(cmds, region);
                }

                if (!debugMethodConfig.TryGetValue("com.sysprogs.esp8266.xt-ocd.flash_start_mode", out val))
                    val = "soft_reset";

                if (val == "soft_reset")
                {
                    try
                    {
                        using (var elfFile = new ELFFile(targetPath))
                        {
                            string pathBase = Path.Combine(Path.GetDirectoryName(targetPath), Path.GetFileName(targetPath));
                            string status;
                            int appMode = ESP8266BinaryImage.DetectAppMode(elfFile, out status);
                            if (appMode != 0)
                            {
                                if (System.Windows.Forms.MessageBox.Show("The soft reset mechanism is not compatible with the OTA images. Use the jump-to-entry reset instead?", "VisualGDB", System.Windows.Forms.MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Warning) == System.Windows.Forms.DialogResult.Yes)
                                    val = "entry_point";
                            }
                        }
                    }
                    catch
                    {

                    }
                }

                if (val == "soft_reset" || val == "entry_point")
                {
                    string entry = "0x40000080";

                    if (val == "entry_point")
                    {
                        using (ELFFile elf = new ELFFile(targetPath))
                        {
                            foreach (var sec in elf.AllSections)
                            {
                                if (!sec.PresentInMemory || !sec.HasData || sec.Type != ELFFile.SectionType.SHT_PROGBITS)
                                    continue;

                                bool isInRAM = false;
                                if (sec.VirtualAddress >= 0x3FFE8000 && sec.VirtualAddress < (0x3FFE8000 + 81920))
                                    isInRAM = true;
                                else if (sec.VirtualAddress >= 0x40100000 && sec.VirtualAddress <= (0x40100000 + 32768))
                                    isInRAM = true;

                                if (isInRAM)
                                {
                                    cmds.Add(new CustomStartStep(string.Format("restore {0} binary 0x{1:x} 0x{2:x} 0x{3:x}", targetPath.Replace('\\', '/'),
                                        sec.VirtualAddress - sec.OffsetInFile, sec.OffsetInFile, sec.OffsetInFile + sec.Size))
                                    { CheckResult = true, ErrorMessage = "Failed to program the " + sec.SectionName + " section" });
                                }
                            }
                        }

                        entry = "$$DEBUG:ENTRY_POINT$$";
                    }

                    cmds.Add(new CustomStartStep("set $ps=0x20",
                        "set $epc2=" + entry,
                        "set $sp=$$DEBUG:INITIAL_STACK_POINTER$$",
                        "set $vecbase=0x40000000",
                        "$$com.sysprogs.esp8266.interrupt_disable_command$$",
                        "set $intclear=-1",
                        "set $intenable=0",
                        "set $eps2=0x20",
                        "set $icountlevel=0"));
                    result.InitialHardBreakpointExpression = "*$$DEBUG:ENTRY_POINT$$";
                }
                else
                    cmds.Add(new CustomStartStep(isOpenOCD ? "mon reset halt" : "maint packet R"));
            }
            else
            {
                cmds.Add(new CustomStartStep("load",
                    "set $ps=0x20",
                    "set $epc2=$$DEBUG:ENTRY_POINT$$",
                    "set $sp=$$DEBUG:INITIAL_STACK_POINTER$$",
                    "set $vecbase=0x40000000",
                    "$$com.sysprogs.esp8266.interrupt_disable_command$$",
                    "set $ccompare=0",
                    "set $intclear=-1",
                    "set $intenable=0",
                    "set $eps2=0x20",
                    "set $icountlevel=0"));
            }

            return result;
        }
Esempio n. 29
0
        /// <summary>
        /// Load native symbols and modules (i.e. DAC, DBI).
        /// </summary>
        /// <param name="callback">called back for each symbol file loaded</param>
        /// <param name="parameter">callback parameter</param>
        /// <param name="config">Target configuration: Windows, Linux or OSX</param>
        /// <param name="moduleFilePath">module path</param>
        /// <param name="address">module base address</param>
        /// <param name="size">module size</param>
        /// <param name="readMemory">read memory callback delegate</param>
        private void LoadNativeSymbols(
            IntPtr self,
            SymbolFileCallback callback,
            IntPtr parameter,
            RuntimeConfiguration config,
            string moduleFilePath,
            ulong address,
            uint size)
        {
            if (_symbolService.IsSymbolStoreEnabled)
            {
                try
                {
                    Stream       stream    = MemoryService.CreateMemoryStream(address, size);
                    KeyGenerator generator = null;
                    if (config == RuntimeConfiguration.UnixCore)
                    {
                        var elfFile = new ELFFile(new StreamAddressSpace(stream), 0, true);
                        generator = new ELFFileKeyGenerator(Tracer.Instance, elfFile, moduleFilePath);
                    }
                    else if (config == RuntimeConfiguration.OSXCore)
                    {
                        var machOFile = new MachOFile(new StreamAddressSpace(stream), 0, true);
                        generator = new MachOFileKeyGenerator(Tracer.Instance, machOFile, moduleFilePath);
                    }
                    else if (config == RuntimeConfiguration.WindowsCore || config == RuntimeConfiguration.WindowsDesktop)
                    {
                        var peFile = new PEFile(new StreamAddressSpace(stream), true);
                        generator = new PEFileKeyGenerator(Tracer.Instance, peFile, moduleFilePath);
                    }
                    else
                    {
                        Trace.TraceError("LoadNativeSymbols: unsupported config {0}", config);
                    }
                    if (generator != null)
                    {
                        IEnumerable <SymbolStoreKey> keys = generator.GetKeys(KeyTypeFlags.SymbolKey | KeyTypeFlags.DacDbiKeys);
                        foreach (SymbolStoreKey key in keys)
                        {
                            string moduleFileName = Path.GetFileName(key.FullPathName);
                            Trace.TraceInformation("{0} {1}", key.FullPathName, key.Index);

                            string downloadFilePath = _symbolService.DownloadFile(key);
                            if (downloadFilePath != null)
                            {
                                Trace.TraceInformation("{0}: {1}", moduleFileName, downloadFilePath);
                                callback(parameter, moduleFileName, downloadFilePath);
                            }
                        }
                    }
                }
                catch (Exception ex) when
                    (ex is DiagnosticsException ||
                    ex is BadInputFormatException ||
                    ex is InvalidVirtualAddressException ||
                    ex is ArgumentOutOfRangeException ||
                    ex is IndexOutOfRangeException ||
                    ex is TaskCanceledException)
                {
                    Trace.TraceError("{0} address {1:X16}: {2}", moduleFilePath, address, ex.Message);
                }
            }
        }
Esempio n. 30
0
 public ELFFileKeyGenerator(ITracer tracer, ELFFile elfFile, string path)
     : base(tracer)
 {
     _elfFile = elfFile;
     _path    = path;
 }
Esempio n. 31
0
        /// <summary>
        /// Load native symbols and modules (i.e. dac, dbi).
        /// </summary>
        /// <param name="callback">called back for each symbol file loaded</param>
        /// <param name="parameter">callback parameter</param>
        /// <param name="moduleDirectory">module path</param>
        /// <param name="moduleFileName">module file name</param>
        /// <param name="address">module base address</param>
        /// <param name="size">module size</param>
        /// <param name="readMemory">read memory callback delegate</param>
        internal static void LoadNativeSymbols(SymbolFileCallback callback, IntPtr parameter, string tempDirectory, string moduleDirectory, string moduleFileName,
                                               ulong address, int size, ReadMemoryDelegate readMemory)
        {
            if (s_symbolStore != null)
            {
                Debug.Assert(s_tracer != null);
                string       path      = Path.Combine(moduleDirectory, moduleFileName);
                Stream       stream    = new TargetStream(address, size, readMemory);
                KeyTypeFlags flags     = KeyTypeFlags.SymbolKey | KeyTypeFlags.ClrKeys;
                KeyGenerator generator = null;

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                {
                    var elfFile = new ELFFile(new StreamAddressSpace(stream), 0, true);
                    generator = new ELFFileKeyGenerator(s_tracer, elfFile, path);
                }
                else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                {
                    var machOFile = new MachOFile(new StreamAddressSpace(stream), 0, true);
                    generator = new MachOFileKeyGenerator(s_tracer, machOFile, path);
                }
                else
                {
                    return;
                }

                try
                {
                    IEnumerable <SymbolStoreKey> keys = generator.GetKeys(flags);
                    foreach (SymbolStoreKey key in keys)
                    {
                        string symbolFileName = Path.GetFileName(key.FullPathName);
                        s_tracer.Verbose("{0} {1}", key.FullPathName, key.Index);

                        // Don't download the sos binaries that come with the runtime
                        if (symbolFileName != "SOS.NETCore.dll" && !symbolFileName.StartsWith("libsos."))
                        {
                            using (SymbolStoreFile file = GetSymbolStoreFile(key))
                            {
                                if (file != null)
                                {
                                    try
                                    {
                                        string downloadFileName = file.FileName;

                                        // If the downloaded doesn't already exists on disk in the cache, then write it to a temporary location.
                                        if (!File.Exists(downloadFileName))
                                        {
                                            downloadFileName = Path.Combine(tempDirectory, symbolFileName);

                                            using (Stream destinationStream = File.OpenWrite(downloadFileName)) {
                                                file.Stream.CopyTo(destinationStream);
                                            }
                                            s_tracer.WriteLine("Downloaded symbol file {0}", key.FullPathName);
                                        }
                                        s_tracer.Information("{0}: {1}", symbolFileName, downloadFileName);
                                        callback(parameter, symbolFileName, downloadFileName);
                                    }
                                    catch (Exception ex) when(ex is UnauthorizedAccessException || ex is DirectoryNotFoundException)
                                    {
                                        s_tracer.Error("{0}", ex.Message);
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception ex) when(ex is BadInputFormatException || ex is InvalidVirtualAddressException)
                {
                    s_tracer.Error("Exception: {0}/{1}: {2:X16}", moduleDirectory, moduleFileName, address);
                }
            }
        }
Esempio n. 32
0
        internal void VerifyCoreDump()
        {
            foreach (string inputFile in GetInputFiles())
            {
                Console.WriteLine($"{inputFile}");

                using Stream inputStream = File.Open(inputFile, FileMode.Open, FileAccess.Read, FileShare.Read);
                var dataSource = new StreamAddressSpace(inputStream);
                var core       = new ELFCoreFile(dataSource);

                if (Tracer.Enabled)
                {
                    foreach (ELFProgramSegment segment in core.Segments)
                    {
                        Tracer.Information("{0:X16}-{1:X16} {2:X8} {3:X8} {4}",
                                           segment.Header.VirtualAddress.Value,
                                           segment.Header.VirtualAddress + segment.Header.VirtualSize,
                                           segment.Header.FileOffset.Value,
                                           (ulong)segment.Header.FileSize,
                                           segment.Header.Type);
                    }
                }

                foreach (ELFLoadedImage image in core.LoadedImages)
                {
                    Console.WriteLine("{0:X16} {1}", image.LoadAddress, image.Path);
                    Exception elfException   = null;
                    Exception machoException = null;
                    Exception peException    = null;
                    try
                    {
                        ELFFile elfFile = image.Image;
                        if (elfFile.IsValid())
                        {
                            try
                            {
                                byte[] buildid = elfFile.BuildID;
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine("                 ELF file invalid build id - {0}", ex.Message);
                            }
                            foreach (ELFProgramSegment segment in elfFile.Segments)
                            {
                                Tracer.Verbose("                 {0:X16}-{1:X16} file off {2:X8} file size {3:X8} {4}",
                                               segment.Header.VirtualAddress.Value,
                                               segment.Header.VirtualAddress + segment.Header.VirtualSize,
                                               segment.Header.FileOffset.Value,
                                               (ulong)segment.Header.FileSize,
                                               segment.Header.Type);

                                if (segment.Header.Type == ELFProgramHeaderType.Note ||
                                    segment.Header.Type == ELFProgramHeaderType.Dynamic ||
                                    segment.Header.Type == ELFProgramHeaderType.GnuEHFrame)
                                {
                                    try
                                    {
                                        byte[] data = segment.Contents.Read(0, (uint)segment.Header.VirtualSize);
                                    }
                                    catch (Exception ex)
                                    {
                                        Console.WriteLine("                 ELF file segment {0} virt addr {1:X16} virt size {2:X8} INVALID - {3}",
                                                          segment.Header.Type, segment.Header.VirtualAddress, segment.Header.VirtualSize, ex.Message);
                                    }
                                }
                            }

                            // The ELF module was valid try next module
                            continue;
                        }
                    }
                    catch (Exception ex)
                    {
                        elfException = ex;
                    }

                    IAddressSpace addressSpace = new RelativeAddressSpace(core.DataSource, image.LoadAddress, core.DataSource.Length);
                    try
                    {
                        var machoFile = new MachOFile(addressSpace);
                        if (machoFile.IsValid())
                        {
                            try
                            {
                                byte[] uuid = machoFile.Uuid;
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine("                 MachO file invalid uuid - {0}", ex.Message);
                            }
                            foreach (MachSegment segment in machoFile.Segments)
                            {
                                Tracer.Verbose("                 {0:X16}-{1:X16} offset {2:X16} size {3:X16} {4} {5}",
                                               (ulong)segment.LoadCommand.VMAddress,
                                               segment.LoadCommand.VMAddress + segment.LoadCommand.VMSize,
                                               (ulong)segment.LoadCommand.FileOffset,
                                               (ulong)segment.LoadCommand.FileSize,
                                               segment.LoadCommand.Command,
                                               segment.LoadCommand.SegName);

                                foreach (MachSection section in segment.Sections)
                                {
                                    Tracer.Verbose("                         addr {0:X16} size {1:X16} offset {2:X8} {3}",
                                                   (ulong)section.Address,
                                                   (ulong)section.Size,
                                                   section.Offset,
                                                   section.SectionName);
                                }
                            }

                            // The MachO module was valid try next module
                            continue;
                        }
                    }
                    catch (Exception ex)
                    {
                        machoException = ex;
                    }

                    try
                    {
                        var peFile = new PEFile(addressSpace, true);
                        if (peFile.IsValid())
                        {
                            // The PE module was valid try next module
                            continue;
                        }
                    }
                    catch (Exception ex)
                    {
                        peException = ex;
                    }

                    Console.WriteLine("{0:X16} invalid image - {1}", image.LoadAddress, image.Path);
                    if (elfException != null)
                    {
                        Tracer.Verbose("ELF {0}", elfException.Message);
                    }
                    if (machoException != null)
                    {
                        Tracer.Verbose("MachO {0}", machoException.Message);
                    }
                    if (peException != null)
                    {
                        Tracer.Verbose("PE {0}", peException.Message);
                    }
                }

                ulong segmentsTotal = core.Segments.Max(s => s.Header.FileOffset + s.Header.FileSize);
                if (segmentsTotal > dataSource.Length)
                {
                    Console.WriteLine($"ERROR: Core file not complete: file size 0x{dataSource.Length:X8} segments total 0x{segmentsTotal:X8}");
                }
            }
        }
Esempio n. 33
0
        public static void ServeOTAFiles(int port, ESP8266BinaryImage.ParsedHeader hdr, params string[] elfFiles)
        {
            TcpListener listener = new TcpListener(port);
            byte[] buffer = new byte[1024];
            OTAImage[] images = new OTAImage[2];

            foreach (var fn in elfFiles)
                if (fn != null)
                    using (var elfFile = new ELFFile(fn))
                    {
                        string status;
                        int appMode = ESP8266BinaryImage.DetectAppMode(elfFile, out status);
                        if (appMode == 0)
                        {
                            Console.WriteLine(fn + " is not an OTA ELF file. Skipping...");
                            continue;
                        }

                        var img = ESP8266BinaryImage.MakeBootloaderBasedImageFromELFFile(elfFile, hdr, appMode);
                        using (var ms = new MemoryStream())
                        {
                            img.Save(ms);
                            images[appMode - 1].Data = ms.ToArray();
                            images[appMode - 1].File = fn;
                        }
                    }

            Console.WriteLine($"Ready to serve the following files:");
            Console.WriteLine($"APP1: {images[0].File ?? "(none)"}");
            Console.WriteLine($"APP2: {images[1].File ?? "(none)"}");
            Console.WriteLine($"Waiting for connection on port {port}...");
            listener.Start();
            for (;;)
            {
                using (var sock = listener.AcceptSocket())
                {
                    Console.WriteLine($"Incoming connection from {(sock.RemoteEndPoint as IPEndPoint).Address}");

                    StringBuilder requestBuilder = new StringBuilder();
                    while (!requestBuilder.ToString().Contains("\r\n\r"))
                    {
                        int done = sock.Receive(buffer);
                        requestBuilder.Append(Encoding.UTF8.GetString(buffer, 0, done));
                    }

                    string request = requestBuilder.ToString();
                    string[] parts = request.Split(' ');
                    if (parts.Length < 3)
                        throw new Exception("Invalid HTTP request: " + request);

                    string url = parts[1];
                    Console.WriteLine("Received request for " + url);
                    int otaIndex = (url.ToLower().Contains("user2") ? 1 : 0);
                    if (images[otaIndex].Data == null)
                        throw new Exception($"No OTA image for app{otaIndex + 1} is provided. Please check your linker scripts.");

                    string reply = string.Format("HTTP/1.0 200 OK\r\nContent-Type: application/octet-stream\r\nContent-Length: {0}\r\n\r\n", images[otaIndex].Data.Length);
                    var r = Encoding.UTF8.GetBytes(reply);
                    sock.Send(r);

                    if (parts[0] == "GET")
                    {
                        Console.Write($"Serving {Path.GetFileName(images[otaIndex].File)}...\r\n");

                        using (var ms = new MemoryStream(images[otaIndex].Data))
                        {
                            int totalDone = 0;
                            for (;;)
                            {
                                int done = ms.Read(buffer, 0, buffer.Length);
                                if (done == 0)
                                    break;
                                sock.Send(buffer, done, SocketFlags.None);
                                totalDone += done;

                                int percent = (int)((totalDone * 100) / ms.Length);
                                int progress = percent / 5;
                                Console.Write($"\r[{new string('#', progress).PadRight(20)}] {percent}%");
                            }
                        }
                        Console.WriteLine("\r\nFile sent successfully\n");
                        break;
                    }
                }
            }
            listener.Stop();
        }
Esempio n. 34
0
        public static void ServeOTAFiles(int port, ESP8266BinaryImage.ESP8266ImageHeader hdr, params string[] elfFiles)
        {
            TcpListener listener = new TcpListener(port);

            byte[]     buffer = new byte[1024];
            OTAImage[] images = new OTAImage[2];

            foreach (var fn in elfFiles)
            {
                if (fn != null)
                {
                    using (var elfFile = new ELFFile(fn))
                    {
                        string status;
                        int    appMode = ESP8266BinaryImage.DetectAppMode(elfFile, out status);
                        if (appMode == 0)
                        {
                            Console.WriteLine(fn + " is not an OTA ELF file. Skipping...");
                            continue;
                        }

                        var img = ESP8266BinaryImage.MakeBootloaderBasedImageFromELFFile(elfFile, hdr, appMode);
                        using (var ms = new MemoryStream())
                        {
                            img.Save(ms);
                            images[appMode - 1].Data = ms.ToArray();
                            images[appMode - 1].File = fn;
                        }
                    }
                }
            }


            Console.WriteLine($"Ready to serve the following files:");
            Console.WriteLine($"APP1: {images[0].File ?? "(none)"}");
            Console.WriteLine($"APP2: {images[1].File ?? "(none)"}");
            Console.WriteLine($"Waiting for connection on port {port}...");
            listener.Start();
            for (;;)
            {
                using (var sock = listener.AcceptSocket())
                {
                    Console.WriteLine($"Incoming connection from {(sock.RemoteEndPoint as IPEndPoint).Address}");

                    StringBuilder requestBuilder = new StringBuilder();
                    while (!requestBuilder.ToString().Contains("\r\n\r"))
                    {
                        int done = sock.Receive(buffer);
                        requestBuilder.Append(Encoding.UTF8.GetString(buffer, 0, done));
                    }

                    string   request = requestBuilder.ToString();
                    string[] parts   = request.Split(' ');
                    if (parts.Length < 3)
                    {
                        throw new Exception("Invalid HTTP request: " + request);
                    }

                    string url = parts[1];
                    Console.WriteLine("Received request for " + url);
                    int otaIndex = (url.ToLower().Contains("user2") ? 1 : 0);
                    if (images[otaIndex].Data == null)
                    {
                        throw new Exception($"No OTA image for app{otaIndex + 1} is provided. Please check your linker scripts.");
                    }

                    string reply = string.Format("HTTP/1.0 200 OK\r\nContent-Type: application/octet-stream\r\nContent-Length: {0}\r\n\r\n", images[otaIndex].Data.Length);
                    var    r     = Encoding.UTF8.GetBytes(reply);
                    sock.Send(r);

                    if (parts[0] == "GET")
                    {
                        Console.Write($"Serving {Path.GetFileName(images[otaIndex].File)}...\r\n");

                        using (var ms = new MemoryStream(images[otaIndex].Data))
                        {
                            int totalDone = 0;
                            for (;;)
                            {
                                int done = ms.Read(buffer, 0, buffer.Length);
                                if (done == 0)
                                {
                                    break;
                                }
                                sock.Send(buffer, done, SocketFlags.None);
                                totalDone += done;

                                int percent  = (int)((totalDone * 100) / ms.Length);
                                int progress = percent / 5;
                                Console.Write($"\r[{new string('#', progress).PadRight(20)}] {percent}%");
                            }
                        }
                        Console.WriteLine("\r\nFile sent successfully\n");
                        break;
                    }
                }
            }
            listener.Stop();
        }