Exemple #1
0
        /// <summary>
        /// Parses an integer key that was stored as a string, and checks to see if the
        /// value falls within an acceptable range.
        /// </summary>
        /// <param name="keyStr">Integer key, in string form.</param>
        /// <param name="fileLen">Length of file, for range check.</param>
        /// <param name="fieldName">Name of field, for error messages.</param>
        /// <param name="report">Error report object.</param>
        /// <param name="intKey">Returned integer key.</param>
        /// <returns>True on success, false on failure.</returns>
        private static bool ParseValidateKey(string keyStr, int fileLen, string fieldName,
                                             FileLoadReport report, out int intKey)
        {
            if (!int.TryParse(keyStr, out intKey))
            {
                report.Add(FileLoadItem.Type.Warning,
                           Properties.Resources.ERR_INVALID_INT_VALUE + " (" +
                           fieldName + ": " + keyStr + ")");
                return(false);
            }

            // Shouldn't allow DisplayList.Line.HEADER_COMMENT_OFFSET on anything but
            // LongComment.  Maybe "bool allowNegativeKeys"?
            if (intKey < fileLen &&
                (intKey >= 0 || intKey == DisplayList.Line.HEADER_COMMENT_OFFSET))
            {
                return(true);
            }
            else
            {
                report.Add(FileLoadItem.Type.Warning,
                           Properties.Resources.ERR_INVALID_KEY_VALUE +
                           " (" + fieldName + ": " + intKey + ")");
                return(false);
            }
        }
Exemple #2
0
        /// <summary>
        /// Attempts to load the specified plugin.  If the plugin is already loaded, this
        /// does nothing.  If not, the assembly is loaded an an instance is created.
        /// </summary>
        /// <param name="scriptIdent">Script identifier.</param>
        /// <param name="report">Report with errors and warnings.</param>
        /// <returns>True on success.</returns>
        public bool LoadPlugin(string scriptIdent, out FileLoadReport report)
        {
            // Make sure the most recent version is compiled.
            string dllPath = PluginDllCache.GenerateScriptDll(scriptIdent,
                                                              mProject.ProjectPathName, out report);

            if (dllPath == null)
            {
                return(false);
            }

            if (DomainManager == null)
            {
                if (mActivePlugins.TryGetValue(scriptIdent, out IPlugin plugin))
                {
                    return(true);
                }
                Assembly asm = Assembly.LoadFile(dllPath);
                plugin = PluginDllCache.ConstructIPlugin(asm);
                mActivePlugins.Add(scriptIdent, plugin);
                report = new FileLoadReport(dllPath);       // empty report
                return(true);
            }
            else
            {
                IPlugin plugin = DomainManager.PluginMgr.LoadPlugin(dllPath, scriptIdent);
                return(plugin != null);
            }
        }
Exemple #3
0
 /// <summary>
 /// Creates a LocalVariableTable from a SerLocalVariableTable.
 /// </summary>
 /// <param name="serTable">Deserialized data.</param>
 /// <param name="contentVersion">Serialization version.</param>
 /// <param name="report">Error report object.</param>
 /// <param name="outLvt">Created LocalVariableTable</param>
 /// <returns>True on success.</returns>
 private static bool CreateLocalVariableTable(SerLocalVariableTable serTable,
                                              int contentVersion, FileLoadReport report, out LocalVariableTable outLvt)
 {
     outLvt = new LocalVariableTable();
     outLvt.ClearPrevious = serTable.ClearPrevious;
     foreach (SerDefSymbol serDef in serTable.Variables)
     {
         // Force the "has width" field to true for local variables, because it's
         // non-optional there.  This is really only needed for loading projects
         // created in v1.3, which didn't have the "has width" property.
         serDef.HasWidth = true;
         if (!CreateDefSymbol(serDef, contentVersion, report, out DefSymbol defSym))
         {
             return(false);
         }
         if (!defSym.IsVariable)
         {
             // not expected to happen; skip it
             Debug.WriteLine("Found local variable with bad source: " +
                             defSym.SymbolSource);
             string str = string.Format(Res.Strings.ERR_BAD_LOCAL_VARIABLE_FMT,
                                        defSym);
             report.Add(FileLoadItem.Type.Warning, str);
             continue;
         }
         outLvt.AddOrReplace(defSym);
     }
     return(true);
 }
Exemple #4
0
        private DisasmProject InstantiateProject(string dataPathName,
                                                 out FileLoadReport projectLoadReport)
        {
            DisasmProject project = new DisasmProject();

            // always use AppDomain sandbox

            projectLoadReport = null;

            int testNum = GetTestNum(dataPathName);

            if (testNum < 2000)
            {
                // create new disasm project for data file
                byte[] fileData;
                try {
                    fileData = LoadDataFile(dataPathName);
                } catch (Exception ex) {
                    ReportErrMsg(ex.Message);
                    return(null);
                }

                project.Initialize(fileData.Length);
                project.PrepForNew(fileData, Path.GetFileName(dataPathName));
                // no platform symbols to load
            }
            else
            {
                // deserialize project file, failing if we can't find it
                string projectPathName = dataPathName + ProjectFile.FILENAME_EXT;
                if (!ProjectFile.DeserializeFromFile(projectPathName,
                                                     project, out projectLoadReport))
                {
                    ReportErrMsg(projectLoadReport.Format());
                    return(null);
                }

                byte[] fileData;
                try {
                    fileData = LoadDataFile(dataPathName);
                } catch (Exception ex) {
                    ReportErrMsg(ex.Message);
                    return(null);
                }

                project.SetFileData(fileData, Path.GetFileName(dataPathName));
                project.ProjectPathName = projectPathName;
                project.LoadExternalFiles();
            }

            TaskTimer genTimer = new TaskTimer();
            DebugLog  genLog   = new DebugLog();

            genLog.SetMinPriority(DebugLog.Priority.Silent);
            project.Analyze(UndoableChange.ReanalysisScope.CodeAndData, genLog, genTimer);

            return(project);
        }
Exemple #5
0
        /// <summary>
        /// Prepares the DLL for the specified script, compiling it if necessary.
        /// </summary>
        /// <param name="scriptIdent">Script identifier.</param>
        /// <param name="projectPathName">Project file name, used for naming project-local
        ///   files.  May be empty if the project hasn't been named yet (in which case
        ///   project-local files will cause a failure).</param>
        /// <param name="report">Report with errors and warnings.</param>
        /// <returns>Full path to DLL, or null if compilation failed.</returns>
        public static string GenerateScriptDll(string scriptIdent, string projectPathName,
                                               out FileLoadReport report)
        {
            ExternalFile ef = ExternalFile.CreateFromIdent(scriptIdent);

            if (ef == null)
            {
                Debug.Assert(false);
                report = new FileLoadReport("CreateFromIdent failed");
                return(null);
            }
            string projectDir = string.Empty;

            if (!string.IsNullOrEmpty(projectPathName))
            {
                projectDir = Path.GetDirectoryName(projectPathName);
            }
            string srcPathName = ef.GetPathName(projectDir);

            // Fail if the source script doesn't exist.  If a previously-compiled DLL is present
            // we could just continue to use it, but that seems contrary to expectation, and
            // means that you won't notice that your project is broken until you clear out
            // the DLL directory.
            if (!File.Exists(srcPathName))
            {
                report = new FileLoadReport(srcPathName);
                report.Add(FileLoadItem.Type.Error,
                           string.Format(Properties.Resources.ERR_FILE_NOT_FOUND, srcPathName));
                return(null);
            }

            string destFileName = ef.GenerateDllName(projectPathName);
            string destPathName = Path.Combine(GetPluginDirPath(), destFileName);

            // Compile if necessary.
            if (FileUtil.FileMissingOrOlder(destPathName, srcPathName))
            {
                Debug.WriteLine("Compiling " + srcPathName + " to " + destPathName);
                Assembly asm = CompileCode(srcPathName, destPathName, out report);
                if (asm == null)
                {
                    return(null);
                }
            }
            else
            {
                Debug.WriteLine("NOT recompiling " + srcPathName);
                report = new FileLoadReport(srcPathName);
            }

            return(destPathName);
        }
Exemple #6
0
        /// <summary>
        /// Compiles the script from the specified pathname into an Assembly.
        /// </summary>
        /// <param name="scriptPathName">Script pathname.</param>
        /// <param name="dllPathName">Full pathname for output DLL.</param>
        /// <param name="report">Errors and warnings reported by the compiler.</param>
        /// <returns>Reference to script instance, or null on failure.</returns>
        private static Assembly CompileCode(string scriptPathName, string dllPathName,
                                            out FileLoadReport report)
        {
            report = new FileLoadReport(scriptPathName);

            // To get C#6 (and later) features, a NuGet package must be installed, and
            // some "black magic" must be invoked.
            // See https://stackoverflow.com/a/40311406/294248 and nearby answers.

            Microsoft.CSharp.CSharpCodeProvider csProvider =
                new Microsoft.CSharp.CSharpCodeProvider();

            CompilerParameters parms = new CompilerParameters();

            // We want a DLL, not an EXE.
            parms.GenerateExecutable = false;
            // Save to disk so other AppDomain can load it.
            parms.GenerateInMemory = false;
            // Be vocal about warnings.
            parms.WarningLevel = 3;
            // Optimization is nice.
            parms.CompilerOptions = "/optimize";
            // Output file name.  Must be named appropriately so it can be found.
            parms.OutputAssembly = dllPathName;
            // Add dependencies.
            parms.ReferencedAssemblies.AddRange(sRefAssem);
#if DEBUG
            // This creates a .pdb file, which allows breakpoints to work.
            parms.IncludeDebugInformation = true;
#endif

            // Using the "from file" version has an advantage over the "from source"
            // version in that the debugger can find the source file, so things like
            // breakpoints work correctly.
            CompilerResults         cr  = csProvider.CompileAssemblyFromFile(parms, scriptPathName);
            CompilerErrorCollection cec = cr.Errors;
            foreach (CompilerError ce in cr.Errors)
            {
                report.Add(ce.Line, ce.Column,
                           ce.IsWarning ? FileLoadItem.Type.Warning : FileLoadItem.Type.Error,
                           ce.ErrorText);
            }
            if (cr.Errors.HasErrors)
            {
                return(null);
            }
            else
            {
                Debug.WriteLine("Compilation successful");
                return(cr.CompiledAssembly);
            }
        }
Exemple #7
0
 /// <summary>
 /// Creates a Symbol from a SerSymbol.
 /// </summary>
 /// <param name="ssym">Deserialized data.</param>
 /// <param name="report">Error report object.</param>
 /// <param name="outSym"></param>
 /// <returns>True on success.</returns>
 private static bool CreateSymbol(SerSymbol ssym, FileLoadReport report,
                                  out Symbol outSym)
 {
     outSym = null;
     Symbol.Source source;
     Symbol.Type   type;
     try {
         source = (Symbol.Source)Enum.Parse(typeof(Symbol.Source), ssym.Source);
         type   = (Symbol.Type)Enum.Parse(typeof(Symbol.Type), ssym.Type);
     } catch (ArgumentException) {
         report.Add(FileLoadItem.Type.Warning, Properties.Resources.ERR_BAD_SYMBOL_ST +
                    ": " + ssym.Source + "/" + ssym.Type);
         return(false);
     }
     outSym = new Symbol(ssym.Label, ssym.Value, source, type /*, ssym.IsExport*/);
     return(true);
 }
Exemple #8
0
        /// <summary>
        /// Creates a DefSymbol from a SerDefSymbol.
        /// </summary>
        /// <param name="serDefSym">Deserialized data.</param>
        /// <param name="contentVersion">Serialization version.</param>
        /// <param name="report">Error report object.</param>
        /// <param name="outDefSym">Created symbol.</param>
        /// <returns></returns>
        private static bool CreateDefSymbol(SerDefSymbol serDefSym, int contentVersion,
                                            FileLoadReport report, out DefSymbol outDefSym)
        {
            outDefSym = null;

            if (!CreateSymbol(serDefSym, report, out Symbol sym))
            {
                return(false);
            }
            if (!CreateFormatDescriptor(serDefSym.DataDescriptor, contentVersion, report,
                                        out FormatDescriptor dfd))
            {
                return(false);
            }
            DefSymbol.DirectionFlags direction;
            if (string.IsNullOrEmpty(serDefSym.Direction))
            {
                direction = DefSymbol.DirectionFlags.ReadWrite;
            }
            else
            {
                try {
                    direction = (DefSymbol.DirectionFlags)
                                Enum.Parse(typeof(DefSymbol.DirectionFlags), serDefSym.Direction);
                } catch (ArgumentException) {
                    report.Add(FileLoadItem.Type.Warning, Res.Strings.ERR_BAD_DEF_SYMBOL_DIR +
                               ": " + serDefSym.Direction);
                    return(false);
                }
            }


            DefSymbol.MultiAddressMask multiMask = null;
            if (serDefSym.MultiMask != null)
            {
                multiMask = new DefSymbol.MultiAddressMask(serDefSym.MultiMask.CompareMask,
                                                           serDefSym.MultiMask.CompareValue, serDefSym.MultiMask.AddressMask);
            }

            outDefSym = DefSymbol.Create(sym, dfd, serDefSym.HasWidth, serDefSym.Comment,
                                         direction, multiMask);
            return(true);
        }
Exemple #9
0
        /// <summary>
        /// Reads the specified file and deserializes it into the project.
        /// </summary>
        /// <param name="pathName">Input path name.</param>
        /// <param name="proj">Project to deserialize into.</param>
        /// <param name="report">File load report, which may contain errors or warnings.</param>
        /// <returns>True on success.</returns>
        public static bool DeserializeFromFile(string pathName, DisasmProject proj,
                                               out FileLoadReport report)
        {
            Debug.WriteLine("Deserializing '" + pathName + "'");
            report = new FileLoadReport(pathName);
            string serializedData;

            try {
                serializedData = File.ReadAllText(pathName);
            } catch (Exception ex) {
                report.Add(FileLoadItem.Type.Error, Properties.Resources.ERR_PROJECT_LOAD_FAIL +
                           ": " + ex.Message);
                return(false);
            }

            if (serializedData.StartsWith(SerializableProjectFile1.MAGIC))
            {
                // File is a match for SerializableProjectFile1.  Strip header and deserialize.
                serializedData = serializedData.Substring(SerializableProjectFile1.MAGIC.Length);
                try {
                    bool ok = SerializableProjectFile1.DeserializeProject(serializedData,
                                                                          proj, report);
                    if (ok)
                    {
                        proj.UpdateCpuDef();
                    }
                    return(ok);
                } catch (Exception ex) {
                    // Ideally this won't happen -- errors should be caught explicitly.  This
                    // is a catch-all to keep us from crashing on expectedly bad input.
                    report.Add(FileLoadItem.Type.Error,
                               Properties.Resources.ERR_PROJECT_FILE_CORRUPT + ": " + ex);
                    return(false);
                }
            }
            else
            {
                report.Add(FileLoadItem.Type.Error, Properties.Resources.ERR_NOT_PROJECT_FILE);
                return(false);
            }
        }
Exemple #10
0
        /// <summary>
        /// Attempts to load the specified plugin.  If the plugin is already loaded, this
        /// does nothing.  If not, the assembly is loaded and an instance is created.
        /// </summary>
        /// <param name="scriptIdent">Script identifier.</param>
        /// <param name="report">Report with errors and warnings.</param>
        /// <returns>True on success.</returns>
        public bool LoadPlugin(string scriptIdent, out FileLoadReport report)
        {
            // Make sure the most recent version is compiled.
            string dllPath = PluginDllCache.GenerateScriptDll(scriptIdent,
                                                              mProject.ProjectPathName, out report);

            if (dllPath == null)
            {
                return(false);
            }

            if (DomainMgr == null)
            {
                if (mActivePlugins.TryGetValue(scriptIdent, out IPlugin plugin))
                {
                    return(true);
                }
                Assembly asm = Assembly.LoadFile(dllPath);
                plugin = PluginDllCache.ConstructIPlugin(asm);
                mActivePlugins.Add(scriptIdent, plugin);
                report = new FileLoadReport(dllPath);       // empty report
                return(true);
            }
            else
            {
                CheckHealth();
                IPlugin plugin = DomainMgr.PluginMgr.LoadPlugin(dllPath, scriptIdent,
                                                                out string failMsg);
                if (plugin == null)
                {
                    report.Add(FileLoadItem.Type.Error, "Failed loading plugin: " + failMsg);
                }
                else
                {
                    mLoadedPlugins.Add(new LoadedPluginPath(scriptIdent, dllPath));
                }
                return(plugin != null);
            }
        }
Exemple #11
0
 /// <summary>
 /// Creates a FormatDescriptor from a SerFormatDescriptor.
 /// </summary>
 /// <param name="sfd">Deserialized data.</param>
 /// <param name="report">Error report object.</param>
 /// <param name="dfd">Created FormatDescriptor.</param>
 /// <returns>True on success.</returns>
 private static bool CreateFormatDescriptor(SerFormatDescriptor sfd,
                                            FileLoadReport report, out FormatDescriptor dfd)
 {
     dfd = null;
     FormatDescriptor.Type    format;
     FormatDescriptor.SubType subFormat;
     try {
         format = (FormatDescriptor.Type)Enum.Parse(
             typeof(FormatDescriptor.Type), sfd.Format);
         subFormat = (FormatDescriptor.SubType)Enum.Parse(
             typeof(FormatDescriptor.SubType), sfd.SubFormat);
     } catch (ArgumentException) {
         report.Add(FileLoadItem.Type.Warning, Properties.Resources.ERR_BAD_FD_FORMAT +
                    ": " + sfd.Format + "/" + sfd.SubFormat);
         return(false);
     }
     if (sfd.SymbolRef == null)
     {
         dfd = FormatDescriptor.Create(sfd.Length, format, subFormat);
     }
     else
     {
         WeakSymbolRef.Part part;
         try {
             part = (WeakSymbolRef.Part)Enum.Parse(
                 typeof(WeakSymbolRef.Part), sfd.SymbolRef.Part);
         } catch (ArgumentException) {
             report.Add(FileLoadItem.Type.Warning,
                        Properties.Resources.ERR_BAD_SYMREF_PART +
                        ": " + sfd.SymbolRef.Part);
             return(false);
         }
         dfd = FormatDescriptor.Create(sfd.Length,
                                       new WeakSymbolRef(sfd.SymbolRef.Label, part),
                                       format == FormatDescriptor.Type.NumericBE);
     }
     return(true);
 }
Exemple #12
0
        /// <summary>
        /// Deserializes an augmented JSON string into a DisasmProject.
        /// </summary>
        /// <param name="cereal">Serialized data.</param>
        /// <param name="proj">Project to populate.</param>
        /// <param name="report">Error report object.</param>
        /// <returns>True on success, false on fatal error.</returns>
        public static bool DeserializeProject(string cereal, DisasmProject proj,
                                              FileLoadReport report)
        {
            JavaScriptSerializer     ser = new JavaScriptSerializer();
            SerializableProjectFile1 spf;

            try {
                spf = ser.Deserialize <SerializableProjectFile1>(cereal);
            } catch (Exception ex) {
                // The deserializer seems to be stuffing the entire data stream into the
                // exception, which we don't really want, so cap it at 256 chars.
                string msg = ex.Message;
                if (msg.Length > 256)
                {
                    msg = msg.Substring(0, 256) + " [...]";
                }
                report.Add(FileLoadItem.Type.Error, Properties.Resources.ERR_PROJECT_FILE_CORRUPT +
                           ": " + msg);
                return(false);
            }

            if (spf._ContentVersion > ProjectFile.CONTENT_VERSION)
            {
                // Post a warning.
                report.Add(FileLoadItem.Type.Notice, Properties.Resources.PROJECT_FROM_NEWER_APP);
            }

            if (spf.FileDataLength <= 0)
            {
                report.Add(FileLoadItem.Type.Error, Properties.Resources.ERR_BAD_FILE_LENGTH +
                           ": " + spf.FileDataLength);
                return(false);
            }

            // Initialize the object and set a few simple items.
            proj.Initialize(spf.FileDataLength);
            proj.SetFileCrc((uint)spf.FileDataCrc32);

            // Deserialize ProjectProperties: misc items.
            proj.ProjectProps.CpuType = Asm65.CpuDef.GetCpuTypeFromName(spf.ProjectProps.CpuName);
            proj.ProjectProps.IncludeUndocumentedInstr = spf.ProjectProps.IncludeUndocumentedInstr;
            proj.ProjectProps.EntryFlags = Asm65.StatusFlags.FromInt(spf.ProjectProps.EntryFlags);
            if (Enum.TryParse <AutoLabel.Style>(spf.ProjectProps.AutoLabelStyle,
                                                out AutoLabel.Style als))
            {
                proj.ProjectProps.AutoLabelStyle = als;
            }
            else
            {
                // unknown value, leave as default
            }
            proj.ProjectProps.AnalysisParams = new ProjectProperties.AnalysisParameters();
            proj.ProjectProps.AnalysisParams.AnalyzeUncategorizedData =
                spf.ProjectProps.AnalysisParams.AnalyzeUncategorizedData;
            proj.ProjectProps.AnalysisParams.MinCharsForString =
                spf.ProjectProps.AnalysisParams.MinCharsForString;
            proj.ProjectProps.AnalysisParams.SeekNearbyTargets =
                spf.ProjectProps.AnalysisParams.SeekNearbyTargets;

            // Deserialize ProjectProperties: external file identifiers.
            Debug.Assert(proj.ProjectProps.PlatformSymbolFileIdentifiers.Count == 0);
            foreach (string str in spf.ProjectProps.PlatformSymbolFileIdentifiers)
            {
                proj.ProjectProps.PlatformSymbolFileIdentifiers.Add(str);
            }
            Debug.Assert(proj.ProjectProps.ExtensionScriptFileIdentifiers.Count == 0);
            foreach (string str in spf.ProjectProps.ExtensionScriptFileIdentifiers)
            {
                proj.ProjectProps.ExtensionScriptFileIdentifiers.Add(str);
            }

            // Deserialize ProjectProperties: project symbols.
            foreach (KeyValuePair <string, SerDefSymbol> kvp in spf.ProjectProps.ProjectSyms)
            {
                if (!CreateSymbol(kvp.Value, report, out Symbol sym))
                {
                    continue;
                }
                if (!CreateFormatDescriptor(kvp.Value.DataDescriptor, report,
                                            out FormatDescriptor dfd))
                {
                    continue;
                }

                proj.ProjectProps.ProjectSyms[sym.Label] =
                    new DefSymbol(sym, dfd, kvp.Value.Comment);
            }

            // Deserialize address map.
            foreach (SerAddressMap addr in spf.AddressMap)
            {
                proj.AddrMap.Set(addr.Offset, addr.Addr);
            }

            // Deserialize type hints.  Default value in new array as NoHint, so we don't
            // need to write those.  They should not have been recorded in the file.
            foreach (SerTypeHintRange range in spf.TypeHints)
            {
                if (range.Low < 0 || range.High >= spf.FileDataLength || range.Low > range.High)
                {
                    report.Add(FileLoadItem.Type.Warning, Properties.Resources.ERR_BAD_RANGE +
                               ": " + Properties.Resources.PROJECT_FIELD_TYPE_HINT +
                               " +" + range.Low.ToString("x6") + " - +" + range.High.ToString("x6"));
                    continue;
                }
                CodeAnalysis.TypeHint hint;
                try {
                    hint = (CodeAnalysis.TypeHint)Enum.Parse(
                        typeof(CodeAnalysis.TypeHint), range.Hint);
                } catch (ArgumentException) {
                    report.Add(FileLoadItem.Type.Warning, Properties.Resources.ERR_BAD_TYPE_HINT +
                               ": " + range.Hint);
                    continue;
                }
                for (int i = range.Low; i <= range.High; i++)
                {
                    proj.TypeHints[i] = hint;
                }
            }

            // Deserialize status flag overrides.
            foreach (KeyValuePair <string, int> kvp in spf.StatusFlagOverrides)
            {
                if (!ParseValidateKey(kvp.Key, spf.FileDataLength,
                                      Properties.Resources.PROJECT_FIELD_STATUS_FLAGS, report, out int intKey))
                {
                    continue;
                }
                proj.StatusFlagOverrides[intKey] = Asm65.StatusFlags.FromInt(kvp.Value);
            }

            // Deserialize comments.
            foreach (KeyValuePair <string, string> kvp in spf.Comments)
            {
                if (!ParseValidateKey(kvp.Key, spf.FileDataLength,
                                      Properties.Resources.PROJECT_FIELD_COMMENT, report, out int intKey))
                {
                    continue;
                }
                proj.Comments[intKey] = kvp.Value;
            }

            // Deserialize long comments.
            foreach (KeyValuePair <string, SerMultiLineComment> kvp in spf.LongComments)
            {
                if (!ParseValidateKey(kvp.Key, spf.FileDataLength,
                                      Properties.Resources.PROJECT_FIELD_LONG_COMMENT, report, out int intKey))
                {
                    continue;
                }
                proj.LongComments[intKey] = new MultiLineComment(kvp.Value.Text,
                                                                 kvp.Value.BoxMode, kvp.Value.MaxWidth);
            }

            // Deserialize notes.
            foreach (KeyValuePair <string, SerMultiLineComment> kvp in spf.Notes)
            {
                if (!ParseValidateKey(kvp.Key, spf.FileDataLength,
                                      Properties.Resources.PROJECT_FIELD_NOTE, report, out int intKey))
                {
                    continue;
                }
                proj.Notes[intKey] = new MultiLineComment(kvp.Value.Text,
                                                          Color.FromArgb(kvp.Value.BackgroundColor));
            }

            // Deserialize user-defined labels.
            SortedList <string, string> labelDupCheck =
                new SortedList <string, string>(spf.UserLabels.Count);

            foreach (KeyValuePair <string, SerSymbol> kvp in spf.UserLabels)
            {
                if (!ParseValidateKey(kvp.Key, spf.FileDataLength,
                                      Properties.Resources.PROJECT_FIELD_USER_LABEL, report, out int intKey))
                {
                    continue;
                }

                Symbol.Source source;
                Symbol.Type   type;
                try {
                    source = (Symbol.Source)Enum.Parse(typeof(Symbol.Source), kvp.Value.Source);
                    type   = (Symbol.Type)Enum.Parse(typeof(Symbol.Type), kvp.Value.Type);
                    if (source != Symbol.Source.User)
                    {
                        // User labels are always source=user.  I don't think it really matters,
                        // but best to keep junk out.
                        throw new Exception("wrong source for user label");
                    }
                } catch (ArgumentException) {
                    report.Add(FileLoadItem.Type.Warning, Properties.Resources.ERR_BAD_SYMBOL_ST +
                               ": " + kvp.Value.Source + "/" + kvp.Value.Type);
                    continue;
                }

                // Check for duplicate labels.  We only want to compare label strings, so we
                // can't test UserLabels.ContainsValue (which might be a linear search anyway).
                // Dump the labels into a sorted list.
                if (labelDupCheck.ContainsKey(kvp.Value.Label))
                {
                    report.Add(FileLoadItem.Type.Warning,
                               string.Format(Properties.Resources.ERR_DUPLICATE_LABEL,
                                             kvp.Value.Label, intKey));
                    continue;
                }
                labelDupCheck.Add(kvp.Value.Label, string.Empty);

                proj.UserLabels[intKey] = new Symbol(kvp.Value.Label, kvp.Value.Value,
                                                     source, type);
            }

            // Deserialize operand format descriptors.
            foreach (KeyValuePair <string, SerFormatDescriptor> kvp in spf.OperandFormats)
            {
                if (!ParseValidateKey(kvp.Key, spf.FileDataLength,
                                      Properties.Resources.PROJECT_FIELD_OPERAND_FORMAT, report,
                                      out int intKey))
                {
                    continue;
                }

                if (!CreateFormatDescriptor(kvp.Value, report, out FormatDescriptor dfd))
                {
                    continue;
                }
                if (intKey < 0 || intKey + dfd.Length > spf.FileDataLength)
                {
                    report.Add(FileLoadItem.Type.Warning,
                               string.Format(Properties.Resources.ERR_BAD_FD, intKey));
                    continue;
                }

                // TODO(maybe): check to see if the descriptor straddles an address change.
                //   Not fatal but it'll make things look weird.

                proj.OperandFormats[intKey] = dfd;
            }

            return(true);
        }
Exemple #13
0
        private DisasmProject InstantiateProject(string dataPathName,
                                                 out FileLoadReport projectLoadReport)
        {
            DisasmProject project = new DisasmProject();

            // always use AppDomain sandbox

            projectLoadReport = null;

            int testNum = GetTestNum(dataPathName);

            CpuDef.CpuType cpuType = GetCpuTypeFromNum(testNum);

            if (testNum < 20000)
            {
                // create new disasm project for data file
                byte[] fileData;
                try {
                    fileData = LoadDataFile(dataPathName);
                } catch (Exception ex) {
                    ReportErrMsg(ex.Message);
                    return(null);
                }

                project.Initialize(fileData.Length);
                project.ProjectProps.CpuType = cpuType;
                project.ProjectProps.IncludeUndocumentedInstr = true;
                project.ProjectProps.TwoByteBrk = false;
                project.UpdateCpuDef();
                project.PrepForNew(fileData, Path.GetFileName(dataPathName));
                // no platform symbols to load
            }
            else
            {
                // deserialize project file, failing if we can't find it
                string projectPathName = dataPathName + ProjectFile.FILENAME_EXT;
                if (!ProjectFile.DeserializeFromFile(projectPathName,
                                                     project, out projectLoadReport))
                {
                    ReportErrMsg(projectLoadReport.Format());
                    return(null);
                }

                byte[] fileData;
                try {
                    fileData = LoadDataFile(dataPathName);
                } catch (Exception ex) {
                    ReportErrMsg(ex.Message);
                    return(null);
                }

                FileLoadReport unused = new FileLoadReport("test");
                project.SetFileData(fileData, Path.GetFileName(dataPathName), ref unused);
                project.ProjectPathName = projectPathName;
                string extMsgs = project.LoadExternalFiles();
                if (!string.IsNullOrEmpty(extMsgs))
                {
                    ReportErrMsg(extMsgs);
                    // keep going
                }

                if (project.ProjectProps.CpuType != cpuType)
                {
                    ReportErrMsg("Mismatch CPU type for test " + testNum + ": project wants " +
                                 project.ProjectProps.CpuType);
                    // keep going
                }
            }

            TaskTimer genTimer = new TaskTimer();
            DebugLog  genLog   = new DebugLog();

            genLog.SetMinPriority(DebugLog.Priority.Silent);
            project.Analyze(UndoableChange.ReanalysisScope.CodeAndData, genLog, genTimer);

            return(project);
        }
Exemple #14
0
        /// <summary>
        /// Prepares the DLL for the specified script, compiling it if necessary.
        /// </summary>
        /// <param name="scriptIdent">Script identifier.</param>
        /// <param name="projectPathName">Project file name, used for naming project-local
        ///   files.  May be empty if the project hasn't been named yet (in which case
        ///   project-local files will cause a failure).</param>
        /// <param name="report">Report with errors and warnings.</param>
        /// <returns>Full path to DLL, or null if compilation failed.</returns>
        public static string GenerateScriptDll(string scriptIdent, string projectPathName,
                                               out FileLoadReport report)
        {
            ExternalFile ef = ExternalFile.CreateFromIdent(scriptIdent);

            if (ef == null)
            {
                Debug.Assert(false);
                report = new FileLoadReport("CreateFromIdent failed");
                return(null);
            }
            string projectDir = string.Empty;

            if (!string.IsNullOrEmpty(projectPathName))
            {
                projectDir = Path.GetDirectoryName(projectPathName);
            }
            string srcPathName = ef.GetPathName(projectDir);

            // Fail if the source script doesn't exist.  If a previously-compiled DLL is present
            // we could just continue to use it, but that seems contrary to expectation, and
            // means that you won't notice that your project is broken until you clear out
            // the DLL directory.
            if (!File.Exists(srcPathName))
            {
                report = new FileLoadReport(srcPathName);
                report.Add(FileLoadItem.Type.Error,
                           string.Format(Res.Strings.ERR_FILE_NOT_FOUND_FMT, srcPathName));
                return(null);
            }

            string destFileName = ef.GenerateDllName(projectPathName);
            string destPathName = Path.Combine(GetPluginDirPath(), destFileName);

            // Compile if necessary.  We do this if the source code is newer, or if the
            // DLLs that plugins depend on have been updated.  (We're checking the dates on
            // the DLLs the app uses, not the copy the plugins use, but earlier we made sure
            // that they were the same.  This test doesn't handle the case where the DLLs
            // get rolled back, but that's probably not interesting for us.)
            bool needCompile = FileUtil.IsFileMissingOrOlder(destPathName, srcPathName) ||
                               FileUtil.IsFileMissingOrOlder(destPathName,
                                                             typeof(PluginCommon.PluginManager).Assembly.Location) ||
                               FileUtil.IsFileMissingOrOlder(destPathName,
                                                             typeof(CommonUtil.CRC32).Assembly.Location);

            if (needCompile)
            {
                Debug.WriteLine("Compiling " + srcPathName + " to " + destPathName);
                Assembly asm = CompileCode(srcPathName, destPathName, out report);
                if (asm == null)
                {
                    return(null);
                }
            }
            else
            {
                Debug.WriteLine("NOT recompiling " + srcPathName);
                report = new FileLoadReport(srcPathName);
            }

            return(destPathName);
        }
Exemple #15
0
        /// <summary>
        /// Loads platform symbols.
        /// </summary>
        /// <param name="fileIdent">Relative pathname of file to open.</param>
        /// <param name="report">Report of warnings and errors.</param>
        /// <returns>True on success (no errors), false on failure.</returns>
        public bool LoadFromFile(string fileIdent, string projectDir, out FileLoadReport report)
        {
            // These files shouldn't be enormous.  Do it the easy way.
            report = new FileLoadReport(fileIdent);

            ExternalFile ef = ExternalFile.CreateFromIdent(fileIdent);

            if (ef == null)
            {
                report.Add(FileLoadItem.Type.Error,
                           CommonUtil.Properties.Resources.ERR_FILE_NOT_FOUND + ": " + fileIdent);
                return(false);
            }

            string pathName = ef.GetPathName(projectDir);

            if (pathName == null)
            {
                report.Add(FileLoadItem.Type.Error,
                           Properties.Resources.ERR_BAD_IDENT + ": " + fileIdent);
                return(false);
            }
            string[] lines;
            try {
                lines = File.ReadAllLines(pathName);
            } catch (IOException ioe) {
                Debug.WriteLine("Platform symbol load failed: " + ioe);
                report.Add(FileLoadItem.Type.Error,
                           CommonUtil.Properties.Resources.ERR_FILE_NOT_FOUND + ": " + pathName);
                return(false);
            }

            string tag = string.Empty;

            int lineNum = 0;

            foreach (string line in lines)
            {
                lineNum++;      // first line is line 1, says Vim and VisualStudio
                if (string.IsNullOrEmpty(line) || line[0] == ';')
                {
                    // ignore
                }
                else if (line[0] == '*')
                {
                    if (line.StartsWith(TAG_CMD))
                    {
                        tag = ParseTag(line);
                    }
                    else
                    {
                        // Do something clever with *SYNOPSIS?
                        Debug.WriteLine("CMD: " + line);
                    }
                }
                else
                {
                    MatchCollection matches = sNameValueRegex.Matches(line);
                    if (matches.Count == 1)
                    {
                        //Debug.WriteLine("GOT '" + matches[0].Groups[1] + "' " +
                        //    matches[0].Groups[2] + " '" + matches[0].Groups[3] + "'");
                        string label   = matches[0].Groups[1].Value;
                        bool   isConst = (matches[0].Groups[2].Value[0] == '=');
                        string badParseMsg;
                        int    value, numBase;
                        bool   parseOk;
                        if (isConst)
                        {
                            // Allow various numeric options, and preserve the value.
                            parseOk = Asm65.Number.TryParseInt(matches[0].Groups[3].Value,
                                                               out value, out numBase);
                            badParseMsg =
                                CommonUtil.Properties.Resources.ERR_INVALID_NUMERIC_CONSTANT;
                        }
                        else
                        {
                            // Allow things like "05/1000".  Always hex.
                            numBase = 16;
                            parseOk = Asm65.Address.ParseAddress(matches[0].Groups[3].Value,
                                                                 (1 << 24) - 1, out value);
                            badParseMsg = CommonUtil.Properties.Resources.ERR_INVALID_ADDRESS;
                        }
                        if (!parseOk)
                        {
                            report.Add(lineNum, FileLoadItem.NO_COLUMN, FileLoadItem.Type.Warning,
                                       badParseMsg);
                        }
                        else
                        {
                            string comment = matches[0].Groups[4].Value;
                            if (comment.Length > 0)
                            {
                                // remove ';'
                                comment = comment.Substring(1);
                            }
                            FormatDescriptor.SubType subType =
                                FormatDescriptor.GetSubTypeForBase(numBase);
                            DefSymbol symDef = new DefSymbol(label, value, Symbol.Source.Platform,
                                                             isConst ? Symbol.Type.Constant : Symbol.Type.ExternalAddr,
                                                             subType, comment, tag);
                            if (mSymbols.ContainsKey(label))
                            {
                                // This is very easy to do -- just define the same symbol twice
                                // in the same file.  We don't really need to do anything about
                                // it though.
                                Debug.WriteLine("NOTE: stomping previous definition of " + label);
                            }
                            mSymbols[label] = symDef;
                        }
                    }
                    else
                    {
                        report.Add(lineNum, FileLoadItem.NO_COLUMN, FileLoadItem.Type.Warning,
                                   CommonUtil.Properties.Resources.ERR_SYNTAX);
                    }
                }
            }

            return(!report.HasErrors);
        }
Exemple #16
0
        /// <summary>
        /// Loads platform symbols.
        /// </summary>
        /// <param name="fileIdent">External file identifier of symbol file.</param>
        /// <param name="projectDir">Full path to project directory.</param>
        /// <param name="loadOrdinal">Platform file load order.</param>
        /// <param name="report">Report of warnings and errors.</param>
        /// <returns>True on success (no errors), false on failure.</returns>
        public bool LoadFromFile(string fileIdent, string projectDir, int loadOrdinal,
                                 out FileLoadReport report)
        {
            report = new FileLoadReport(fileIdent);

            ExternalFile ef = ExternalFile.CreateFromIdent(fileIdent);

            if (ef == null)
            {
                report.Add(FileLoadItem.Type.Error,
                           CommonUtil.Properties.Resources.ERR_FILE_NOT_FOUND + ": " + fileIdent);
                return(false);
            }
            string pathName = ef.GetPathName(projectDir);

            if (pathName == null)
            {
                report.Add(FileLoadItem.Type.Error,
                           Res.Strings.ERR_BAD_IDENT + ": " + fileIdent);
                return(false);
            }

            // These files shouldn't be enormous.  Just read the entire thing into a string array.
            string[] lines;
            try {
                lines = File.ReadAllLines(pathName);
            } catch (IOException ioe) {
                Debug.WriteLine("Platform symbol load failed: " + ioe);
                report.Add(FileLoadItem.Type.Error,
                           CommonUtil.Properties.Resources.ERR_FILE_NOT_FOUND + ": " + pathName);
                return(false);
            }

            string tag = string.Empty;

            DefSymbol.MultiAddressMask multiMask = null;

            int lineNum = 0;

            foreach (string line in lines)
            {
                lineNum++;      // first line is line 1, says Vim and VisualStudio
                if (string.IsNullOrEmpty(line) || line[0] == ';')
                {
                    // ignore
                }
                else if (line[0] == '*')
                {
                    if (line.StartsWith(TAG_CMD))
                    {
                        tag = ParseTag(line);
                    }
                    else if (line.StartsWith(MULTI_MASK_CMD))
                    {
                        if (!ParseMask(line, out multiMask, out string badMaskMsg))
                        {
                            report.Add(lineNum, FileLoadItem.NO_COLUMN, FileLoadItem.Type.Warning,
                                       badMaskMsg);
                        }
                        //Debug.WriteLine("Mask is now " + mask.ToString("x6"));
                    }
                    else
                    {
                        // Do something clever with *SYNOPSIS?
                        Debug.WriteLine("Ignoring CMD: " + line);
                    }
                }
                else
                {
                    MatchCollection matches = sNameValueRegex.Matches(line);
                    if (matches.Count == 1)
                    {
                        string label      = matches[0].Groups[GROUP_NAME].Value;
                        char   typeAndDir = matches[0].Groups[GROUP_TYPE].Value[0];
                        bool   isConst    = (typeAndDir == '=');
                        DefSymbol.DirectionFlags direction = DefSymbol.DirectionFlags.ReadWrite;
                        if (typeAndDir == '<')
                        {
                            direction = DefSymbol.DirectionFlags.Read;
                        }
                        else if (typeAndDir == '>')
                        {
                            direction = DefSymbol.DirectionFlags.Write;
                        }

                        string badParseMsg;
                        int    value, numBase;
                        bool   parseOk;
                        string valueStr = matches[0].Groups[GROUP_VALUE].Value;
                        if (isConst)
                        {
                            // Allow various numeric options, and preserve the value.  We
                            // don't limit the value range.
                            parseOk     = Asm65.Number.TryParseInt(valueStr, out value, out numBase);
                            badParseMsg =
                                CommonUtil.Properties.Resources.ERR_INVALID_NUMERIC_CONSTANT;
                        }
                        else if (valueStr.ToUpperInvariant().Equals(ERASE_VALUE_STR))
                        {
                            parseOk     = true;
                            value       = ERASE_VALUE;
                            numBase     = 10;
                            badParseMsg = CommonUtil.Properties.Resources.ERR_INVALID_ADDRESS;
                        }
                        else
                        {
                            // Allow things like "05/1000".  Always hex.
                            numBase = 16;
                            parseOk = Asm65.Address.ParseAddress(valueStr, (1 << 24) - 1,
                                                                 out value);
                            // limit to positive 24-bit values
                            parseOk    &= (value >= 0 && value < 0x01000000);
                            badParseMsg = CommonUtil.Properties.Resources.ERR_INVALID_ADDRESS;
                        }

                        int    width    = -1;
                        string widthStr = matches[0].Groups[GROUP_WIDTH].Value;
                        if (parseOk && !string.IsNullOrEmpty(widthStr))
                        {
                            parseOk = Asm65.Number.TryParseInt(widthStr, out width,
                                                               out int ignoredBase);
                            if (parseOk)
                            {
                                if (width < DefSymbol.MIN_WIDTH || width > DefSymbol.MAX_WIDTH)
                                {
                                    parseOk     = false;
                                    badParseMsg = Res.Strings.ERR_INVALID_WIDTH;
                                }
                            }
                            else
                            {
                                badParseMsg =
                                    CommonUtil.Properties.Resources.ERR_INVALID_NUMERIC_CONSTANT;
                            }
                        }

                        if (parseOk && multiMask != null && !isConst)
                        {
                            // We need to ensure that all possible values fit within the mask.
                            // We don't test AddressValue here, because it's okay for the
                            // canonical value to be outside the masked range.
                            int testWidth = (width > 0) ? width : 1;
                            for (int testValue = value; testValue < value + testWidth; testValue++)
                            {
                                if ((testValue & multiMask.CompareMask) != multiMask.CompareValue)
                                {
                                    parseOk     = false;
                                    badParseMsg = Res.Strings.ERR_VALUE_INCOMPATIBLE_WITH_MASK;
                                    Debug.WriteLine("Mask FAIL: value=" + value.ToString("x6") +
                                                    " width=" + width +
                                                    " testValue=" + testValue.ToString("x6") +
                                                    " mask=" + multiMask);
                                    break;
                                }
                            }
                        }

                        if (!parseOk)
                        {
                            report.Add(lineNum, FileLoadItem.NO_COLUMN, FileLoadItem.Type.Warning,
                                       badParseMsg);
                        }
                        else
                        {
                            string comment = matches[0].Groups[GROUP_COMMENT].Value;
                            if (comment.Length > 0)
                            {
                                // remove ';'
                                comment = comment.Substring(1);
                            }
                            FormatDescriptor.SubType subType =
                                FormatDescriptor.GetSubTypeForBase(numBase);
                            DefSymbol symDef = new DefSymbol(label, value, Symbol.Source.Platform,
                                                             isConst ? Symbol.Type.Constant : Symbol.Type.ExternalAddr,
                                                             subType, width, width > 0, comment, direction, multiMask,
                                                             tag, loadOrdinal, fileIdent);
                            if (mSymbols.ContainsKey(label))
                            {
                                // This is very easy to do -- just define the same symbol twice
                                // in the same file.  We don't really need to do anything about
                                // it though.
                                Debug.WriteLine("NOTE: stomping previous definition of " + label);
                            }
                            mSymbols[label] = symDef;
                        }
                    }
                    else
                    {
                        report.Add(lineNum, FileLoadItem.NO_COLUMN, FileLoadItem.Type.Warning,
                                   CommonUtil.Properties.Resources.ERR_SYNTAX);
                    }
                }
            }

            return(!report.HasErrors);
        }
Exemple #17
0
        /// <summary>
        /// Creates a FormatDescriptor from a SerFormatDescriptor.
        /// </summary>
        /// <param name="sfd">Deserialized data.</param>
        /// <param name="version">Serialization version (CONTENT_VERSION).</param>
        /// <param name="report">Error report object.</param>
        /// <param name="dfd">Created FormatDescriptor.</param>
        /// <returns>True on success.</returns>
        private static bool CreateFormatDescriptor(SerFormatDescriptor sfd, int version,
                                                   FileLoadReport report, out FormatDescriptor dfd)
        {
            dfd = null;
            FormatDescriptor.Type    format;
            FormatDescriptor.SubType subFormat;

            if ("String".Equals(sfd.Format))
            {
                // File version 1 used a different set of enumerated values for defining strings.
                // Parse it out here.
                Debug.Assert(version <= 1);
                subFormat = FormatDescriptor.SubType.ASCII_GENERIC;
                if ("None".Equals(sfd.SubFormat))
                {
                    format = FormatDescriptor.Type.StringGeneric;
                }
                else if ("Reverse".Equals(sfd.SubFormat))
                {
                    format = FormatDescriptor.Type.StringReverse;
                }
                else if ("CString".Equals(sfd.SubFormat))
                {
                    format = FormatDescriptor.Type.StringNullTerm;
                }
                else if ("L8String".Equals(sfd.SubFormat))
                {
                    format = FormatDescriptor.Type.StringL8;
                }
                else if ("L16String".Equals(sfd.SubFormat))
                {
                    format = FormatDescriptor.Type.StringL16;
                }
                else if ("Dci".Equals(sfd.SubFormat))
                {
                    format = FormatDescriptor.Type.StringDci;
                }
                else if ("DciReverse".Equals(sfd.SubFormat))
                {
                    // No longer supported.  Nobody ever used this but the regression tests,
                    // though, so there's no reason to handle this nicely.
                    format    = FormatDescriptor.Type.Dense;
                    subFormat = FormatDescriptor.SubType.None;
                }
                else
                {
                    // No idea what this is; output as dense hex.
                    format    = FormatDescriptor.Type.Dense;
                    subFormat = FormatDescriptor.SubType.None;
                }
                Debug.WriteLine("Found v1 string, fmt=" + format + ", sub=" + subFormat);
                dfd = FormatDescriptor.Create(sfd.Length, format, subFormat);
                return(dfd != null);
            }

            try {
                format = (FormatDescriptor.Type)Enum.Parse(
                    typeof(FormatDescriptor.Type), sfd.Format);
                if (version <= 1 && "Ascii".Equals(sfd.SubFormat))
                {
                    // File version 1 used "Ascii" for all character data in numeric operands.
                    // It applied to both low and high ASCII.
                    subFormat = FormatDescriptor.SubType.ASCII_GENERIC;
                    Debug.WriteLine("Found v1 char, fmt=" + sfd.Format + ", sub=" + sfd.SubFormat);
                }
                else
                {
                    subFormat = (FormatDescriptor.SubType)Enum.Parse(
                        typeof(FormatDescriptor.SubType), sfd.SubFormat);
                }
            } catch (ArgumentException) {
                report.Add(FileLoadItem.Type.Warning, Res.Strings.ERR_BAD_FD_FORMAT +
                           ": " + sfd.Format + "/" + sfd.SubFormat);
                return(false);
            }
            if (sfd.SymbolRef == null)
            {
                dfd = FormatDescriptor.Create(sfd.Length, format, subFormat);
            }
            else
            {
                WeakSymbolRef.Part part;
                try {
                    part = (WeakSymbolRef.Part)Enum.Parse(
                        typeof(WeakSymbolRef.Part), sfd.SymbolRef.Part);
                } catch (ArgumentException) {
                    report.Add(FileLoadItem.Type.Warning,
                               Res.Strings.ERR_BAD_SYMREF_PART +
                               ": " + sfd.SymbolRef.Part);
                    return(false);
                }
                dfd = FormatDescriptor.Create(sfd.Length,
                                              new WeakSymbolRef(sfd.SymbolRef.Label, part),
                                              format == FormatDescriptor.Type.NumericBE);
            }
            return(dfd != null);
        }