diff --git a/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/C/C.jj b/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/C/C.jj
index 83d9c47357..0c558bf4dd 100644
--- a/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/C/C.jj
+++ b/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/C/C.jj
@@ -1922,7 +1922,7 @@ void PragmaSpecifier() : {
{
LOOKAHEAD(3)
PragmaSpecifier() |
- id= ( | | )*
+ id= ( | | | )*
([ [ (ds1=PragmaConstant())+ [ ( ds2=PragmaConstant() ) [ ( ds3=PragmaConstant() ) [ ( PragmaConstant() )+ ] ] ] ] ] )
{
if (id.image.equals("pack") && ds1 != null) {
diff --git a/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/CParserTest.h b/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/CParserTest.h
index 27717692a4..08a2a243c0 100644
--- a/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/CParserTest.h
+++ b/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/CParserTest.h
@@ -176,6 +176,9 @@ int (__stdcall * GetSectionBlock) (
#pragma region Input compatibility macros
+// nothing will parse after this line if the this fails
+ #pragma test for, pragma, with, commas outside parens
+
#pragma warning(disable)
#pragma warning(disable:4035 4793) // re-enable below
diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc
index 1e6dea66b9..62508298f6 100644
--- a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc
+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc
@@ -1404,6 +1404,7 @@ void Architecture::resetDefaultsInternal(void)
alias_block_level = 2; // Block structs and arrays by default, but not more primitive data-types
split_datatype_config = OptionSplitDatatypes::option_struct | OptionSplitDatatypes::option_array
| OptionSplitDatatypes::option_pointer;
+ max_jumptable_size = 1024;
}
/// Reset options that can be modified by the OptionDatabase. This includes
diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh
index 421bed574c..c2c4d8e3c0 100644
--- a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh
+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh
@@ -172,6 +172,7 @@ public:
int4 max_term_duplication; ///< Max terms duplicated without a new variable
int4 max_basetype_size; ///< Maximum size of an "integer" type before creating an array type
int4 min_funcsymbol_size; ///< Minimum size of a function symbol
+ uint4 max_jumptable_size; ///< Maximum number of entries in a single JumpTable
bool aggressive_ext_trim; ///< Aggressively trim inputs that look like they are sign extended
bool readonlypropagate; ///< true if readonly values should be treated as constants
bool infer_pointers; ///< True if we should infer pointers from constants that are likely addresses
diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/double.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/double.cc
index 8eb11963ef..49dd39f4ea 100644
--- a/Ghidra/Features/Decompiler/src/decompile/cpp/double.cc
+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/double.cc
@@ -787,10 +787,14 @@ bool SplitVarnode::isAddrTiedContiguous(Varnode *lo,Varnode *hi,Address &res)
if (!hi->isAddrTied()) return false;
// Make sure there is no explicit symbol that would prevent the pieces from being joined
- SymbolEntry *entry = lo->getSymbolEntry();
- if ((entry != (SymbolEntry *)0)&&(entry->getOffset()==0)) return false;
- entry = hi->getSymbolEntry();
- if ((entry != (SymbolEntry *)0)&&(entry->getOffset()==0)) return false;
+ SymbolEntry *entryLo = lo->getSymbolEntry();
+ SymbolEntry *entryHi = hi->getSymbolEntry();
+ if (entryLo != (SymbolEntry *)0 || entryHi != (SymbolEntry *)0) {
+ if (entryLo == (SymbolEntry *)0 || entryHi == (SymbolEntry *)0)
+ return false; // One is marked with a symbol, the other is not
+ if (entryLo->getSymbol() != entryHi->getSymbol())
+ return false; // They are part of different symbols
+ }
AddrSpace *spc = lo->getSpace();
if (spc != hi->getSpace()) return false;
uintb looffset = lo->getOffset();
@@ -3093,6 +3097,12 @@ bool IndirectForm::verify(Varnode *h,Varnode *l,PcodeOp *ind)
if (affector != PcodeOp::getOpFromConst(indlo->getIn(1)->getAddr())) continue; // hi and lo must be affected by same op
reslo = indlo->getOut();
if (reslo->getSpace()->getType() == IPTR_INTERNAL) return false; // Indirect must not be through a temporary
+ if (reslo->isAddrTied() || reshi->isAddrTied()) {
+ Address addr;
+ // If one piece is address tied, the other must be as well, and they must fit together as contiguous whole
+ if (!SplitVarnode::isAddrTiedContiguous(reslo, reshi, addr))
+ return false;
+ }
return true;
}
return false;
diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc
index ee449456ce..c07aea7235 100644
--- a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc
+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc
@@ -2217,7 +2217,7 @@ void JumpTable::recoverModel(Funcdata *fd)
{
if (jmodel != (JumpModel *)0) {
if (jmodel->isOverride()) { // If preexisting model is override
- jmodel->recoverModel(fd,indirect,0,maxtablesize);
+ jmodel->recoverModel(fd,indirect,0,glb->max_jumptable_size);
return;
}
delete jmodel; // Otherwise this is an old attempt we should remove
@@ -2228,18 +2228,18 @@ void JumpTable::recoverModel(Funcdata *fd)
if (op->code() == CPUI_CALLOTHER) {
JumpAssisted *jassisted = new JumpAssisted(this);
jmodel = jassisted;
- if (jmodel->recoverModel(fd,indirect,addresstable.size(),maxtablesize))
+ if (jmodel->recoverModel(fd,indirect,addresstable.size(),glb->max_jumptable_size))
return;
}
}
JumpBasic *jbasic = new JumpBasic(this);
jmodel = jbasic;
- if (jmodel->recoverModel(fd,indirect,addresstable.size(),maxtablesize))
+ if (jmodel->recoverModel(fd,indirect,addresstable.size(),glb->max_jumptable_size))
return;
jmodel = new JumpBasic2(this);
((JumpBasic2 *)jmodel)->initializeStart(jbasic->getPathMeld());
delete jbasic;
- if (jmodel->recoverModel(fd,indirect,addresstable.size(),maxtablesize))
+ if (jmodel->recoverModel(fd,indirect,addresstable.size(),glb->max_jumptable_size))
return;
delete jmodel;
jmodel = (JumpModel *)0;
@@ -2343,7 +2343,6 @@ JumpTable::JumpTable(Architecture *g,Address ad)
switchVarConsume = ~((uintb)0);
defaultBlock = -1;
lastBlock = -1;
- maxtablesize = 1024;
maxaddsub = 1;
maxleftright = 1;
maxext = 1;
@@ -2364,7 +2363,6 @@ JumpTable::JumpTable(const JumpTable *op2)
switchVarConsume = ~((uintb)0);
defaultBlock = -1;
lastBlock = op2->lastBlock;
- maxtablesize = op2->maxtablesize;
maxaddsub = op2->maxaddsub;
maxleftright = op2->maxleftright;
maxext = op2->maxext;
@@ -2682,7 +2680,7 @@ bool JumpTable::recoverLabels(Funcdata *fd)
}
else {
jmodel = new JumpModelTrivial(this);
- jmodel->recoverModel(fd,indirect,addresstable.size(),maxtablesize);
+ jmodel->recoverModel(fd,indirect,addresstable.size(),glb->max_jumptable_size);
jmodel->buildAddresses(fd,indirect,addresstable,(vector *)0);
trivialSwitchOver();
jmodel->buildLabels(fd,addresstable,label,origmodel);
diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh
index fe3de7cbd1..d985052f38 100644
--- a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh
+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh
@@ -535,7 +535,6 @@ class JumpTable {
uintb switchVarConsume; ///< Bits of the switch variable being consumed
int4 defaultBlock; ///< The out-edge corresponding to the \e default switch destination (-1 = undefined)
int4 lastBlock; ///< Block out-edge corresponding to last entry in the address table
- uint4 maxtablesize; ///< Maximum table size we allow to be built (sanity check)
uint4 maxaddsub; ///< Maximum ADDs or SUBs to normalize
uint4 maxleftright; ///< Maximum shifts to normalize
uint4 maxext; ///< Maximum extensions to normalize
@@ -561,7 +560,6 @@ public:
const Address &getOpAddress(void) const { return opaddress; } ///< Get the address of the BRANCHIND for the switch
PcodeOp *getIndirectOp(void) const { return indirect; } ///< Get the BRANCHIND PcodeOp
void setIndirectOp(PcodeOp *ind) { opaddress = ind->getAddr(); indirect = ind; } ///< Set the BRANCHIND PcodeOp
- void setMaxTableSize(uint4 val) { maxtablesize = val; } ///< Set the maximum entries allowed in the address table
void setNormMax(uint4 maddsub,uint4 mleftright,uint4 mext) {
maxaddsub = maddsub; maxleftright = mleftright; maxext = mext; } ///< Set the switch variable normalization model restrictions
void setOverride(const vector &addrtable,const Address &naddr,uintb h,uintb sv);
diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc
index 14564cbaf2..9979b81400 100644
--- a/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc
+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc
@@ -1160,6 +1160,6 @@ ElementId ELEM_VAL = ElementId("val",8);
ElementId ELEM_VALUE = ElementId("value",9);
ElementId ELEM_VOID = ElementId("void",10);
-ElementId ELEM_UNKNOWN = ElementId("XMLunknown",271); // Number serves as next open index
+ElementId ELEM_UNKNOWN = ElementId("XMLunknown",272); // Number serves as next open index
} // End namespace ghidra
diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc
index 20db3d3d3b..a496b4f8e0 100644
--- a/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc
+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc
@@ -58,6 +58,7 @@ ElementId ELEM_SPLITDATATYPE = ElementId("splitdatatype",270);
ElementId ELEM_STRUCTALIGN = ElementId("structalign",208);
ElementId ELEM_TOGGLERULE = ElementId("togglerule",209);
ElementId ELEM_WARNING = ElementId("warning",210);
+ElementId ELEM_JUMPTABLEMAX = ElementId("jumptablemax",271);
/// If the parameter is "on" return \b true, if "off" return \b false.
/// Any other value causes an exception.
@@ -120,6 +121,7 @@ OptionDatabase::OptionDatabase(Architecture *g)
registerOption(new OptionAllowContextSet());
registerOption(new OptionSetAction());
registerOption(new OptionSetLanguage());
+ registerOption(new OptionJumpTableMax());
registerOption(new OptionJumpLoad());
registerOption(new OptionToggleRule());
registerOption(new OptionAliasBlock());
@@ -794,6 +796,26 @@ string OptionSetLanguage::apply(Architecture *glb,const string &p1,const string
return res;
}
+/// \class OptionJumpTableMax
+/// \brief Set the maximum number of entries that can be recovered for a single jump table
+///
+/// This option is an unsigned integer value used during analysis of jump tables. It serves as a
+/// sanity check that the recovered number of entries for a jump table is reasonable and
+/// also acts as a resource limit on the number of destination addresses that analysis will attempt
+/// to follow from a single indirect jump.
+string OptionJumpTableMax::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const
+
+{
+ istringstream s(p1);
+ s.unsetf(ios::dec | ios::hex | ios::oct);
+ uint4 val = 0;
+ s >> val;
+ if (val==0)
+ throw ParseError("Must specify integer maximum");
+ glb->max_jumptable_size = val;
+ return "Maximum jumptable size set to "+p1;
+}
+
/// \class OptionJumpLoad
/// \brief Toggle whether the decompiler should try to recover the table used to evaluate a switch
///
diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/options.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/options.hh
index a58d77d583..9c08babf21 100644
--- a/Ghidra/Features/Decompiler/src/decompile/cpp/options.hh
+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/options.hh
@@ -64,6 +64,7 @@ extern ElementId ELEM_SPLITDATATYPE; ///< Marshaling element \
extern ElementId ELEM_STRUCTALIGN; ///< Marshaling element \
extern ElementId ELEM_TOGGLERULE; ///< Marshaling element \
extern ElementId ELEM_WARNING; ///< Marshaling element \
+extern ElementId ELEM_JUMPTABLEMAX; ///< Marshaling element \
/// \brief Base class for options classes that affect the configuration of the Architecture object
///
@@ -293,6 +294,12 @@ public:
virtual string apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const;
};
+class OptionJumpTableMax : public ArchOption {
+public:
+ OptionJumpTableMax(void) { name = "jumptablemax"; } ///< Constructor
+ virtual string apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const;
+};
+
class OptionJumpLoad : public ArchOption {
public:
OptionJumpLoad(void) { name = "jumpload"; } ///< Constructor
diff --git a/Ghidra/Features/Decompiler/src/decompile/datatests/partialunion.xml b/Ghidra/Features/Decompiler/src/decompile/datatests/partialunion.xml
index 489cba0888..55c9e55e7f 100644
--- a/Ghidra/Features/Decompiler/src/decompile/datatests/partialunion.xml
+++ b/Ghidra/Features/Decompiler/src/decompile/datatests/partialunion.xml
@@ -33,7 +33,7 @@
dec
print C
lo fu partial1
- map unionfacet structunion 1 r0x1006ee 20603f6a8a0b89
+ map unionfacet structunion 1 r0x1006ee 10603f2c20ffa6
dec
print C
quit
diff --git a/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml b/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml
index 94dc93faf1..816c0d771b 100644
--- a/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml
+++ b/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml
@@ -2984,6 +2984,17 @@
+
+ Max Entries per Jumptable
+
+
+ This option sets the maximum number of entries (addresses) that the Decompiler can
+ recover from analyzing a single jumptable. This serves as a sanity check that the recovered
+ dimensions of a jumptable are reasonable and places an upper limit on the sheer number
+ of addresses the Decompiler is willing to trace from a single indirect jump.
+
+
+
diff --git a/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerOptions.html b/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerOptions.html
index 849c6ae40a..1eb7f91fcf 100644
--- a/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerOptions.html
+++ b/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerOptions.html
@@ -125,6 +125,17 @@
traces control flow into more than the indicated number of instructions.
+
+Max Entries per Jumptable
+
+
+
+ This option sets the maximum number of entries (addresses) that the Decompiler can
+ recover from analyzing a single jumptable. This serves as a sanity check that the recovered
+ dimensions of a jumptable are reasonable and places an upper limit on the sheer number
+ of addresses the Decompiler is willing to trace from a single indirect jump.
+
+
diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileOptions.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileOptions.java
index 80645f95ec..d7e7ff9120 100644
--- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileOptions.java
+++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileOptions.java
@@ -37,8 +37,8 @@ import ghidra.program.model.lang.CompilerSpec.EvaluationModelType;
import ghidra.program.model.listing.Program;
import ghidra.program.model.pcode.ElementId;
import ghidra.program.model.pcode.Encoder;
-import ghidra.program.model.symbol.NameTransformer;
import ghidra.program.model.symbol.IdentityNameTransformer;
+import ghidra.program.model.symbol.NameTransformer;
import ghidra.util.HelpLocation;
/**
@@ -211,6 +211,7 @@ public class DecompileOptions {
public static final int SUGGESTED_DECOMPILE_TIMEOUT_SECS = 30;
public static final int SUGGESTED_MAX_PAYLOAD_BYTES = 50;
public static final int SUGGESTED_MAX_INSTRUCTIONS = 100000; // Must match Architecture::resetDefaultsInternal
+ public static final int SUGGESTED_MAX_JUMPTABLE_ENTRIES = 1024; // Must match Architecture::resetDefaultsInternal
public enum CommentStyleEnum {
@@ -388,11 +389,13 @@ public class DecompileOptions {
private final static String DECOMPILE_TIMEOUT = "Decompiler Timeout (seconds)";
private final static String PAYLOAD_LIMIT = "Decompiler Max-Payload (MBytes)";
private final static String MAX_INSTRUCTIONS = "Max Instructions per Function";
+ private final static String MAX_JUMPTABLE_ENTRIES = "Max Entries per Jumptable";
private final static Boolean LINE_NUMBER_DEF = Boolean.TRUE;
private boolean displayLineNumbers;
private int decompileTimeoutSeconds;
private int payloadLimitMBytes;
private int maxIntructionsPer;
+ private int maxJumpTableEntries;
private int cachedResultsSize;
private DecompilerLanguage displayLanguage; // Output language displayed by the decompiler
@@ -435,6 +438,7 @@ public class DecompileOptions {
decompileTimeoutSeconds = SUGGESTED_DECOMPILE_TIMEOUT_SECS;
payloadLimitMBytes = SUGGESTED_MAX_PAYLOAD_BYTES;
maxIntructionsPer = SUGGESTED_MAX_INSTRUCTIONS;
+ maxJumpTableEntries = SUGGESTED_MAX_JUMPTABLE_ENTRIES;
cachedResultsSize = SUGGESTED_CACHED_RESULTS_SIZE;
nameTransformer = null;
}
@@ -492,6 +496,7 @@ public class DecompileOptions {
decompileTimeoutSeconds = opt.getInt(DECOMPILE_TIMEOUT, SUGGESTED_DECOMPILE_TIMEOUT_SECS);
payloadLimitMBytes = opt.getInt(PAYLOAD_LIMIT, SUGGESTED_MAX_PAYLOAD_BYTES);
maxIntructionsPer = opt.getInt(MAX_INSTRUCTIONS, SUGGESTED_MAX_INSTRUCTIONS);
+ maxJumpTableEntries = opt.getInt(MAX_JUMPTABLE_ENTRIES, SUGGESTED_MAX_JUMPTABLE_ENTRIES);
cachedResultsSize = opt.getInt(CACHED_RESULTS_SIZE_MSG, SUGGESTED_CACHED_RESULTS_SIZE);
grabFromFieldOptions(fieldOptions);
@@ -689,6 +694,9 @@ public class DecompileOptions {
opt.registerOption(MAX_INSTRUCTIONS, SUGGESTED_MAX_INSTRUCTIONS,
new HelpLocation(HelpTopics.DECOMPILER, "GeneralMaxInstruction"),
"The maximum number of instructions decompiled in a single function");
+ opt.registerOption(MAX_JUMPTABLE_ENTRIES, SUGGESTED_MAX_JUMPTABLE_ENTRIES,
+ new HelpLocation(HelpTopics.DECOMPILER, "GeneralMaxJumptable"),
+ "The maximum number of entries that can be recovered from a single jumptable");
opt.registerThemeColorBinding(HIGHLIGHT_CURRENT_VARIABLE_MSG,
HIGHLIGHT_CURRENT_VARIABLE_COLOR.getId(),
new HelpLocation(HelpTopics.DECOMPILER, "DisplayCurrentHighlight"),
@@ -830,6 +838,9 @@ public class DecompileOptions {
if (maxIntructionsPer != SUGGESTED_MAX_INSTRUCTIONS) {
appendOption(encoder, ELEM_MAXINSTRUCTION, Integer.toString(maxIntructionsPer), "", "");
}
+ if (maxJumpTableEntries != SUGGESTED_MAX_JUMPTABLE_ENTRIES) {
+ appendOption(encoder, ELEM_JUMPTABLEMAX, Integer.toString(maxJumpTableEntries), "", "");
+ }
appendOption(encoder, ELEM_PROTOEVAL, protoEvalModel, "", "");
encoder.closeElement(ELEM_OPTIONSLIST);
}
@@ -1222,6 +1233,26 @@ public class DecompileOptions {
maxIntructionsPer = num;
}
+ /**
+ * If the number of entries in a single jumptable exceeds this value, the decompiler will
+ * not recover the table and control flow from the indirect jump corresponding to the table
+ * will not be followed.
+ * @return the maximum number of entries
+ */
+ public int getMaxJumpTableEntries() {
+ return maxJumpTableEntries;
+ }
+
+ /**
+ * Set the maximum number of entries the decompiler will recover from a single jumptable.
+ * If the number exceeds this, the table is not recovered and control flow from the
+ * corresponding indirect jump is not followed.
+ * @param num is the number of entries
+ */
+ public void setMaxJumpTableEntries(int num) {
+ maxJumpTableEntries = num;
+ }
+
/**
* @return the style in which comments are printed in decompiler output
*/
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ElementId.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ElementId.java
index bf9ff4950e..d7a813c678 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ElementId.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ElementId.java
@@ -422,5 +422,6 @@ public record ElementId(String name, int id) {
new ElementId("command_getuseropname", COMMAND_GETUSEROPNAME);
public static final ElementId ELEM_SPLITDATATYPE = new ElementId("splitdatatype", 270);
- public static final ElementId ELEM_UNKNOWN = new ElementId("XMLunknown", 271);
+ public static final ElementId ELEM_JUMPTABLEMAX = new ElementId("jumptablemax", 271);
+ public static final ElementId ELEM_UNKNOWN = new ElementId("XMLunknown", 272);
}