jsilnet 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -6
- package/REFERENCE.md +4 -0
- package/dist/browser/index.js +345 -0
- package/dist/browser/worker.js +42480 -0
- package/package.json +23 -4
- package/src/assembly/instruction-editing.js +165 -0
- package/src/assembly/method-removal.js +789 -0
- package/src/assembly/pointer-table-editing.js +506 -0
- package/src/assembly/portable-pdb-editing.js +441 -0
- package/src/browser/index.d.ts +123 -0
- package/src/browser/index.js +373 -0
- package/src/browser/worker-runtime.js +287 -0
- package/src/browser/worker.js +47 -0
- package/src/index.d.ts +267 -0
- package/src/index.js +107 -1574
- package/src/metadata/portable-pdb.js +2 -2
- package/src/metadata/strong-name.js +84 -83
- package/src/pe/headers.js +1 -1
- package/src/platform/bytes.js +21 -0
- package/src/platform/compression.js +24 -0
- package/src/platform/crypto.js +17 -0
- package/src/types/assembly/instruction-editing.d.ts +33 -0
- package/src/types/assembly/method-removal.d.ts +3 -0
- package/src/types/assembly/pointer-table-editing.d.ts +3 -0
- package/src/types/assembly/portable-pdb-editing.d.ts +23 -0
- package/src/types/binary/errors.d.ts +7 -0
- package/src/types/binary/reader.d.ts +30 -0
- package/src/types/il/body.d.ts +51 -0
- package/src/types/il/instructions.d.ts +33 -0
- package/src/types/il/opcodes.d.ts +2 -0
- package/src/types/il/rewrite.d.ts +38 -0
- package/src/types/index.d.ts +864 -0
- package/src/types/metadata/classic-pdb.d.ts +688 -0
- package/src/types/metadata/custom-attributes.d.ts +28 -0
- package/src/types/metadata/portable-pdb.d.ts +296 -0
- package/src/types/metadata/resources.d.ts +1 -0
- package/src/types/metadata/root-writer.d.ts +1 -0
- package/src/types/metadata/signatures.d.ts +5 -0
- package/src/types/metadata/streams.d.ts +26 -0
- package/src/types/metadata/strong-name.d.ts +11 -0
- package/src/types/metadata/tables.d.ts +25 -0
- package/src/types/metadata/writer.d.ts +16 -0
- package/src/types/pe/headers.d.ts +160 -0
- package/src/types/platform/bytes.d.ts +3 -0
- package/src/types/platform/compression.d.ts +2 -0
- package/src/types/platform/crypto.d.ts +4 -0
- package/src/types/resolution/module.d.ts +12 -0
- package/src/types/writer/patch.d.ts +4 -0
- package/src/types/writer/pe.d.ts +9 -0
- package/src/types/writer/structural.d.ts +4 -0
package/src/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { createHash } from "
|
|
1
|
+
import { createHash } from "./platform/crypto.js";
|
|
2
|
+
import { equalBytes } from "./platform/bytes.js";
|
|
2
3
|
import { FormatError, UnsupportedFormatError } from "./binary/errors.js";
|
|
3
4
|
import {
|
|
4
5
|
parseEmbeddedPortablePdbData,
|
|
@@ -31,17 +32,14 @@ import {
|
|
|
31
32
|
} from "./metadata/classic-pdb.js";
|
|
32
33
|
import { parseMethodBody } from "./il/body.js";
|
|
33
34
|
import { encodeInstruction, encodeOpcode, formatInstruction, getInstructionSize } from "./il/instructions.js";
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
createStructuralState,
|
|
37
|
-
insertInstruction as insertStructuralInstruction,
|
|
38
|
-
layoutStructuralState,
|
|
39
|
-
removeInstruction as removeStructuralInstruction,
|
|
40
|
-
updateStructuralOperand
|
|
41
|
-
} from "./il/rewrite.js";
|
|
35
|
+
import { createStructuralState } from "./il/rewrite.js";
|
|
42
36
|
import { resolveMethodParameters, resolveTypes } from "./resolution/module.js";
|
|
43
37
|
import { applyPatches, createOperandPatches } from "./writer/patch.js";
|
|
44
38
|
import { serializeStructural } from "./writer/structural.js";
|
|
39
|
+
import { createInstructionEditor } from "./assembly/instruction-editing.js";
|
|
40
|
+
import { createPointerTableEditor } from "./assembly/pointer-table-editing.js";
|
|
41
|
+
import { createPortablePdbEditor } from "./assembly/portable-pdb-editing.js";
|
|
42
|
+
import { createMethodRemovalEditor } from "./assembly/method-removal.js";
|
|
45
43
|
import { appendBlobHeap, appendStringHeap, appendUserStringHeap } from "./metadata/writer.js";
|
|
46
44
|
import { parseManifestResources } from "./metadata/resources.js";
|
|
47
45
|
import {
|
|
@@ -53,28 +51,7 @@ import {
|
|
|
53
51
|
remapEmbeddedPortablePdbTypeDefinitions as remapPortablePdbTypeDefinitions,
|
|
54
52
|
removeEmbeddedPortablePdbMethod as removePortablePdbMethod,
|
|
55
53
|
refreshEmbeddedPortablePdbId,
|
|
56
|
-
|
|
57
|
-
addEmbeddedPortablePdbSource as addPortablePdbSource,
|
|
58
|
-
removeEmbeddedPortablePdbSourceLink as removePortablePdbSourceLink,
|
|
59
|
-
removeEmbeddedPortablePdbSource as removePortablePdbSource,
|
|
60
|
-
removeEmbeddedPortablePdbCustomDebugInformation as removePortablePdbCustomDebugInformation,
|
|
61
|
-
replaceEmbeddedPortablePdbMethodOffsets as replacePortablePdbMethodOffsets,
|
|
62
|
-
addEmbeddedPortablePdbDocument as addPortablePdbDocument,
|
|
63
|
-
insertEmbeddedPortablePdbDocument as insertPortablePdbDocument,
|
|
64
|
-
addEmbeddedPortablePdbTypeDefinitionDocuments as addPortablePdbTypeDefinitionDocuments,
|
|
65
|
-
removeEmbeddedPortablePdbDocument as removePortablePdbDocument,
|
|
66
|
-
replaceEmbeddedPortablePdbDocumentMetadata as replacePortablePdbDocumentMetadata,
|
|
67
|
-
replaceEmbeddedPortablePdbTypeDefinitionDocuments as replacePortablePdbTypeDefinitionDocuments,
|
|
68
|
-
replaceEmbeddedPortablePdbDocumentName as replacePortablePdbDocumentName,
|
|
69
|
-
replaceEmbeddedPortablePdbLocalScope as replacePortablePdbLocalScope,
|
|
70
|
-
replaceEmbeddedPortablePdbLocalVariable as replacePortablePdbLocalVariable,
|
|
71
|
-
replaceEmbeddedPortablePdbLocalConstant as replacePortablePdbLocalConstant,
|
|
72
|
-
replaceEmbeddedPortablePdbCustomDebugInformation as replacePortablePdbCustomDebugInformation,
|
|
73
|
-
replaceEmbeddedPortablePdbMethodDocument as replacePortablePdbMethodDocument,
|
|
74
|
-
replaceEmbeddedPortablePdbImportScope as replacePortablePdbImportScope,
|
|
75
|
-
replaceEmbeddedPortablePdbSequencePoints as replacePortablePdbSequencePoints,
|
|
76
|
-
replaceEmbeddedPortablePdbSource as replacePortablePdbSource,
|
|
77
|
-
replaceEmbeddedPortablePdbSourceLink as replacePortablePdbSourceLink
|
|
54
|
+
replaceEmbeddedPortablePdbMethodOffsets as replacePortablePdbMethodOffsets
|
|
78
55
|
} from "./metadata/portable-pdb.js";
|
|
79
56
|
import {
|
|
80
57
|
assertStrongNamePEProfile,
|
|
@@ -1999,6 +1976,33 @@ export class Assembly {
|
|
|
1999
1976
|
#strongNameSignatureSize = 0;
|
|
2000
1977
|
#hasAuthenticodeCertificate;
|
|
2001
1978
|
#hasDebugDirectory;
|
|
1979
|
+
#instructionEditor = createInstructionEditor(this, {
|
|
1980
|
+
ensureEditable: () => this.#ensureEditable(),
|
|
1981
|
+
validateBranchTarget: (body, target) => this.#validateBranchTarget(body, target),
|
|
1982
|
+
createStructuralState: (methodRid) => this.#createStructuralState(methodRid),
|
|
1983
|
+
commitStructuralState: (methodRid, state) => this.#commitStructuralState(methodRid, state),
|
|
1984
|
+
allowedTokenTables,
|
|
1985
|
+
validateInstructionGenericContext
|
|
1986
|
+
});
|
|
1987
|
+
#pointerTableEditor = createPointerTableEditor({
|
|
1988
|
+
ensureEditable: () => this.#ensureEditable(),
|
|
1989
|
+
getBijectivePointerRows,
|
|
1990
|
+
validateGenericVariableReferences,
|
|
1991
|
+
getGenericParameterArity,
|
|
1992
|
+
validateTypeSpecDefinitions,
|
|
1993
|
+
validateTypeSpecGenericContext
|
|
1994
|
+
});
|
|
1995
|
+
#portablePdbEditor = createPortablePdbEditor({
|
|
1996
|
+
ensureEditable: () => this.#ensureEditable(),
|
|
1997
|
+
getPortablePdbForEdit: (...args) => this.#getPortablePdbForEdit(...args)
|
|
1998
|
+
});
|
|
1999
|
+
#methodRemovalEditor = createMethodRemovalEditor({
|
|
2000
|
+
ensureEditable: () => this.#ensureEditable(),
|
|
2001
|
+
ensureTokenRemappingSafe: (...args) => this.#ensureTokenRemappingSafe(...args),
|
|
2002
|
+
getPortablePdbForEdit: (...args) => this.#getPortablePdbForEdit(...args),
|
|
2003
|
+
replaceEmbeddedPortablePdb: (...args) => this.#replaceEmbeddedPortablePdb(...args),
|
|
2004
|
+
getBijectivePointerRows
|
|
2005
|
+
});
|
|
2002
2006
|
|
|
2003
2007
|
constructor(input) {
|
|
2004
2008
|
this.#bytes = input instanceof Uint8Array ? Uint8Array.from(input) : new Uint8Array(input);
|
|
@@ -4038,416 +4042,88 @@ export class Assembly {
|
|
|
4038
4042
|
);
|
|
4039
4043
|
}
|
|
4040
4044
|
|
|
4041
|
-
|
|
4042
|
-
this.#
|
|
4043
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4044
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4045
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4046
|
-
}
|
|
4047
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4048
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4049
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4050
|
-
}
|
|
4051
|
-
const data = addPortablePdbDocument(
|
|
4052
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4053
|
-
name,
|
|
4054
|
-
options
|
|
4055
|
-
);
|
|
4056
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4045
|
+
addEmbeddedPortablePdbDocument(debugEntryIndex, name, options) {
|
|
4046
|
+
return this.#portablePdbEditor.addEmbeddedPortablePdbDocument.call(this, debugEntryIndex, name, options);
|
|
4057
4047
|
}
|
|
4058
4048
|
|
|
4059
|
-
|
|
4060
|
-
this.#
|
|
4061
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4062
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4063
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4064
|
-
}
|
|
4065
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4066
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4067
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4068
|
-
}
|
|
4069
|
-
const data = insertPortablePdbDocument(
|
|
4070
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4071
|
-
options
|
|
4072
|
-
);
|
|
4073
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4049
|
+
insertEmbeddedPortablePdbDocument(debugEntryIndex, options) {
|
|
4050
|
+
return this.#portablePdbEditor.insertEmbeddedPortablePdbDocument.call(this, debugEntryIndex, options);
|
|
4074
4051
|
}
|
|
4075
4052
|
|
|
4076
|
-
|
|
4077
|
-
debugEntryIndex,
|
|
4078
|
-
typeRid,
|
|
4079
|
-
documentRids
|
|
4080
|
-
) {
|
|
4081
|
-
this.#ensureEditable();
|
|
4082
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4083
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4084
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4085
|
-
}
|
|
4086
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4087
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4088
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4089
|
-
}
|
|
4090
|
-
const data = addPortablePdbTypeDefinitionDocuments(
|
|
4091
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4092
|
-
typeRid,
|
|
4093
|
-
documentRids
|
|
4094
|
-
);
|
|
4095
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4053
|
+
addEmbeddedPortablePdbTypeDefinitionDocuments(debugEntryIndex, typeRid, documentRids) {
|
|
4054
|
+
return this.#portablePdbEditor.addEmbeddedPortablePdbTypeDefinitionDocuments.call(this, debugEntryIndex, typeRid, documentRids);
|
|
4096
4055
|
}
|
|
4097
4056
|
|
|
4098
|
-
|
|
4099
|
-
this.#
|
|
4100
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4101
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4102
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4103
|
-
}
|
|
4104
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4105
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4106
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4107
|
-
}
|
|
4108
|
-
const data = removePortablePdbDocument(
|
|
4109
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4110
|
-
documentRid
|
|
4111
|
-
);
|
|
4112
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4057
|
+
removeEmbeddedPortablePdbDocument(debugEntryIndex, documentRid) {
|
|
4058
|
+
return this.#portablePdbEditor.removeEmbeddedPortablePdbDocument.call(this, debugEntryIndex, documentRid);
|
|
4113
4059
|
}
|
|
4114
4060
|
|
|
4115
|
-
|
|
4116
|
-
debugEntryIndex,
|
|
4117
|
-
typeRid,
|
|
4118
|
-
documentRids
|
|
4119
|
-
) {
|
|
4120
|
-
this.#ensureEditable();
|
|
4121
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4122
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4123
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4124
|
-
}
|
|
4125
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4126
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4127
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4128
|
-
}
|
|
4129
|
-
const data = replacePortablePdbTypeDefinitionDocuments(
|
|
4130
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4131
|
-
typeRid,
|
|
4132
|
-
documentRids
|
|
4133
|
-
);
|
|
4134
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4061
|
+
replaceEmbeddedPortablePdbTypeDefinitionDocuments(debugEntryIndex, typeRid, documentRids) {
|
|
4062
|
+
return this.#portablePdbEditor.replaceEmbeddedPortablePdbTypeDefinitionDocuments.call(this, debugEntryIndex, typeRid, documentRids);
|
|
4135
4063
|
}
|
|
4136
4064
|
|
|
4137
|
-
|
|
4138
|
-
this.#
|
|
4139
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4140
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4141
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4142
|
-
}
|
|
4143
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4144
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4145
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4146
|
-
}
|
|
4147
|
-
const data = replacePortablePdbDocumentMetadata(
|
|
4148
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4149
|
-
documentRid,
|
|
4150
|
-
options
|
|
4151
|
-
);
|
|
4152
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4065
|
+
replaceEmbeddedPortablePdbDocumentMetadata(debugEntryIndex, documentRid, options) {
|
|
4066
|
+
return this.#portablePdbEditor.replaceEmbeddedPortablePdbDocumentMetadata.call(this, debugEntryIndex, documentRid, options);
|
|
4153
4067
|
}
|
|
4154
4068
|
|
|
4155
|
-
|
|
4156
|
-
this.#
|
|
4157
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4158
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4159
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4160
|
-
}
|
|
4161
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4162
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4163
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4164
|
-
}
|
|
4165
|
-
const data = replacePortablePdbDocumentName(
|
|
4166
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4167
|
-
documentRid,
|
|
4168
|
-
name,
|
|
4169
|
-
separator
|
|
4170
|
-
);
|
|
4171
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4069
|
+
replaceEmbeddedPortablePdbDocumentName(debugEntryIndex, documentRid, name, separator) {
|
|
4070
|
+
return this.#portablePdbEditor.replaceEmbeddedPortablePdbDocumentName.call(this, debugEntryIndex, documentRid, name, separator);
|
|
4172
4071
|
}
|
|
4173
4072
|
|
|
4174
|
-
|
|
4175
|
-
this.#
|
|
4176
|
-
if (this._portablePdbOffsetBaselines.has(methodRid)) {
|
|
4177
|
-
throw new UnsupportedFormatError(
|
|
4178
|
-
"Portable PDB sequence points cannot be replaced after IL offset remapping has been staged"
|
|
4179
|
-
);
|
|
4180
|
-
}
|
|
4181
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4182
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4183
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4184
|
-
}
|
|
4185
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4186
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4187
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4188
|
-
}
|
|
4189
|
-
const data = replacePortablePdbSequencePoints(
|
|
4190
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4191
|
-
methodRid,
|
|
4192
|
-
sequencePoints
|
|
4193
|
-
);
|
|
4194
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4073
|
+
replaceEmbeddedPortablePdbSequencePoints(debugEntryIndex, methodRid, sequencePoints) {
|
|
4074
|
+
return this.#portablePdbEditor.replaceEmbeddedPortablePdbSequencePoints.call(this, debugEntryIndex, methodRid, sequencePoints);
|
|
4195
4075
|
}
|
|
4196
4076
|
|
|
4197
|
-
|
|
4198
|
-
this.#
|
|
4199
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4200
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4201
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4202
|
-
}
|
|
4203
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4204
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4205
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4206
|
-
}
|
|
4207
|
-
const data = replacePortablePdbMethodDocument(
|
|
4208
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4209
|
-
methodRid,
|
|
4210
|
-
documentRid
|
|
4211
|
-
);
|
|
4212
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4077
|
+
replaceEmbeddedPortablePdbMethodDocument(debugEntryIndex, methodRid, documentRid) {
|
|
4078
|
+
return this.#portablePdbEditor.replaceEmbeddedPortablePdbMethodDocument.call(this, debugEntryIndex, methodRid, documentRid);
|
|
4213
4079
|
}
|
|
4214
4080
|
|
|
4215
|
-
|
|
4216
|
-
this.#
|
|
4217
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4218
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4219
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4220
|
-
}
|
|
4221
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4222
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4223
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4224
|
-
}
|
|
4225
|
-
const data = replacePortablePdbImportScope(
|
|
4226
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4227
|
-
importScopeRid,
|
|
4228
|
-
options
|
|
4229
|
-
);
|
|
4230
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4081
|
+
replaceEmbeddedPortablePdbImportScope(debugEntryIndex, importScopeRid, options) {
|
|
4082
|
+
return this.#portablePdbEditor.replaceEmbeddedPortablePdbImportScope.call(this, debugEntryIndex, importScopeRid, options);
|
|
4231
4083
|
}
|
|
4232
4084
|
|
|
4233
|
-
|
|
4234
|
-
this.#
|
|
4235
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4236
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4237
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4238
|
-
}
|
|
4239
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4240
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4241
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4242
|
-
}
|
|
4243
|
-
const pdb = this.#getPortablePdbForEdit(debugEntryIndex, entry);
|
|
4244
|
-
const localScope = pdb.tables.rows.get(50)?.[localScopeRid - 1];
|
|
4245
|
-
if (!localScope || localScope.rid !== localScopeRid) {
|
|
4246
|
-
throw new RangeError(`Invalid Portable PDB LocalScope row ID ${localScopeRid}`);
|
|
4247
|
-
}
|
|
4248
|
-
if (this._portablePdbOffsetBaselines.has(localScope.Method.rid)) {
|
|
4249
|
-
throw new UnsupportedFormatError(
|
|
4250
|
-
"Portable PDB LocalScope offsets cannot be replaced after IL offset remapping has been staged"
|
|
4251
|
-
);
|
|
4252
|
-
}
|
|
4253
|
-
const data = replacePortablePdbLocalScope(pdb, localScopeRid, options);
|
|
4254
|
-
const updatedPdb = parseEmbeddedPortablePdbData(data, 0, data.length);
|
|
4255
|
-
const updatedScope = updatedPdb.tables.rows.get(50)?.[localScopeRid - 1];
|
|
4256
|
-
const body = this.getMethodBody(localScope.Method.rid);
|
|
4257
|
-
if (!updatedScope || !body) {
|
|
4258
|
-
throw new FormatError(
|
|
4259
|
-
`Portable PDB LocalScope row ${localScopeRid} does not resolve to a method body`
|
|
4260
|
-
);
|
|
4261
|
-
}
|
|
4262
|
-
const isBoundary = (offset) => offset === body.codeSize ||
|
|
4263
|
-
body.instructions.some((instruction) => instruction.offset === offset);
|
|
4264
|
-
const endOffset = updatedScope.StartOffset + updatedScope.Length;
|
|
4265
|
-
if (!isBoundary(updatedScope.StartOffset) || !isBoundary(endOffset)) {
|
|
4266
|
-
throw new FormatError(
|
|
4267
|
-
`Portable PDB LocalScope row ${localScopeRid} does not align with MethodDef ${localScope.Method.rid} instruction boundaries`
|
|
4268
|
-
);
|
|
4269
|
-
}
|
|
4270
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4085
|
+
replaceEmbeddedPortablePdbLocalScope(debugEntryIndex, localScopeRid, options) {
|
|
4086
|
+
return this.#portablePdbEditor.replaceEmbeddedPortablePdbLocalScope.call(this, debugEntryIndex, localScopeRid, options);
|
|
4271
4087
|
}
|
|
4272
4088
|
|
|
4273
|
-
|
|
4274
|
-
this.#
|
|
4275
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4276
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4277
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4278
|
-
}
|
|
4279
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4280
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4281
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4282
|
-
}
|
|
4283
|
-
const data = replacePortablePdbLocalVariable(
|
|
4284
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4285
|
-
localVariableRid,
|
|
4286
|
-
options
|
|
4287
|
-
);
|
|
4288
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4089
|
+
replaceEmbeddedPortablePdbLocalVariable(debugEntryIndex, localVariableRid, options) {
|
|
4090
|
+
return this.#portablePdbEditor.replaceEmbeddedPortablePdbLocalVariable.call(this, debugEntryIndex, localVariableRid, options);
|
|
4289
4091
|
}
|
|
4290
4092
|
|
|
4291
|
-
|
|
4292
|
-
this.#
|
|
4293
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4294
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4295
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4296
|
-
}
|
|
4297
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4298
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4299
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4300
|
-
}
|
|
4301
|
-
const data = replacePortablePdbLocalConstant(
|
|
4302
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4303
|
-
localConstantRid,
|
|
4304
|
-
options
|
|
4305
|
-
);
|
|
4306
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4093
|
+
replaceEmbeddedPortablePdbLocalConstant(debugEntryIndex, localConstantRid, options) {
|
|
4094
|
+
return this.#portablePdbEditor.replaceEmbeddedPortablePdbLocalConstant.call(this, debugEntryIndex, localConstantRid, options);
|
|
4307
4095
|
}
|
|
4308
4096
|
|
|
4309
|
-
|
|
4310
|
-
debugEntryIndex,
|
|
4311
|
-
customDebugInformationRid,
|
|
4312
|
-
value
|
|
4313
|
-
) {
|
|
4314
|
-
this.#ensureEditable();
|
|
4315
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4316
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4317
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4318
|
-
}
|
|
4319
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4320
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4321
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4322
|
-
}
|
|
4323
|
-
const data = replacePortablePdbCustomDebugInformation(
|
|
4324
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4325
|
-
customDebugInformationRid,
|
|
4326
|
-
value
|
|
4327
|
-
);
|
|
4328
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4097
|
+
replaceEmbeddedPortablePdbCustomDebugInformation(debugEntryIndex, customDebugInformationRid, value) {
|
|
4098
|
+
return this.#portablePdbEditor.replaceEmbeddedPortablePdbCustomDebugInformation.call(this, debugEntryIndex, customDebugInformationRid, value);
|
|
4329
4099
|
}
|
|
4330
4100
|
|
|
4331
|
-
|
|
4332
|
-
this.#
|
|
4333
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4334
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4335
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4336
|
-
}
|
|
4337
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4338
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4339
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4340
|
-
}
|
|
4341
|
-
const data = replacePortablePdbSource(
|
|
4342
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4343
|
-
documentRid,
|
|
4344
|
-
source,
|
|
4345
|
-
options
|
|
4346
|
-
);
|
|
4347
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4101
|
+
replaceEmbeddedPortablePdbSource(debugEntryIndex, documentRid, source, options) {
|
|
4102
|
+
return this.#portablePdbEditor.replaceEmbeddedPortablePdbSource.call(this, debugEntryIndex, documentRid, source, options);
|
|
4348
4103
|
}
|
|
4349
4104
|
|
|
4350
|
-
|
|
4351
|
-
this.#
|
|
4352
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4353
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4354
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4355
|
-
}
|
|
4356
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4357
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4358
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4359
|
-
}
|
|
4360
|
-
const data = addPortablePdbSource(
|
|
4361
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4362
|
-
documentRid,
|
|
4363
|
-
source,
|
|
4364
|
-
options
|
|
4365
|
-
);
|
|
4366
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4105
|
+
addEmbeddedPortablePdbSource(debugEntryIndex, documentRid, source, options) {
|
|
4106
|
+
return this.#portablePdbEditor.addEmbeddedPortablePdbSource.call(this, debugEntryIndex, documentRid, source, options);
|
|
4367
4107
|
}
|
|
4368
4108
|
|
|
4369
|
-
|
|
4370
|
-
this.#
|
|
4371
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4372
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4373
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4374
|
-
}
|
|
4375
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4376
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4377
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4378
|
-
}
|
|
4379
|
-
const data = removePortablePdbSource(
|
|
4380
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4381
|
-
documentRid
|
|
4382
|
-
);
|
|
4383
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4109
|
+
removeEmbeddedPortablePdbSource(debugEntryIndex, documentRid) {
|
|
4110
|
+
return this.#portablePdbEditor.removeEmbeddedPortablePdbSource.call(this, debugEntryIndex, documentRid);
|
|
4384
4111
|
}
|
|
4385
4112
|
|
|
4386
|
-
|
|
4387
|
-
this.#
|
|
4388
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4389
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4390
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4391
|
-
}
|
|
4392
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4393
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4394
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4395
|
-
}
|
|
4396
|
-
const data = removePortablePdbCustomDebugInformation(
|
|
4397
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4398
|
-
recordRid
|
|
4399
|
-
);
|
|
4400
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4113
|
+
removeEmbeddedPortablePdbCustomDebugInformation(debugEntryIndex, recordRid) {
|
|
4114
|
+
return this.#portablePdbEditor.removeEmbeddedPortablePdbCustomDebugInformation.call(this, debugEntryIndex, recordRid);
|
|
4401
4115
|
}
|
|
4402
4116
|
|
|
4403
|
-
|
|
4404
|
-
this.#
|
|
4405
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4406
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4407
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4408
|
-
}
|
|
4409
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4410
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4411
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4412
|
-
}
|
|
4413
|
-
const data = replacePortablePdbSourceLink(
|
|
4414
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4415
|
-
sourceLink
|
|
4416
|
-
);
|
|
4417
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4117
|
+
replaceEmbeddedPortablePdbSourceLink(debugEntryIndex, sourceLink) {
|
|
4118
|
+
return this.#portablePdbEditor.replaceEmbeddedPortablePdbSourceLink.call(this, debugEntryIndex, sourceLink);
|
|
4418
4119
|
}
|
|
4419
4120
|
|
|
4420
|
-
|
|
4421
|
-
this.#
|
|
4422
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4423
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4424
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4425
|
-
}
|
|
4426
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4427
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4428
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4429
|
-
}
|
|
4430
|
-
const data = removePortablePdbSourceLink(
|
|
4431
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry)
|
|
4432
|
-
);
|
|
4433
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4121
|
+
removeEmbeddedPortablePdbSourceLink(debugEntryIndex) {
|
|
4122
|
+
return this.#portablePdbEditor.removeEmbeddedPortablePdbSourceLink.call(this, debugEntryIndex);
|
|
4434
4123
|
}
|
|
4435
4124
|
|
|
4436
|
-
|
|
4437
|
-
this.#
|
|
4438
|
-
if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
|
|
4439
|
-
debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
|
|
4440
|
-
throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
|
|
4441
|
-
}
|
|
4442
|
-
const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
4443
|
-
if (entry.type !== 17 || !entry.embeddedPortablePdb) {
|
|
4444
|
-
throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
|
|
4445
|
-
}
|
|
4446
|
-
const data = addPortablePdbSourceLink(
|
|
4447
|
-
this.#getPortablePdbForEdit(debugEntryIndex, entry),
|
|
4448
|
-
sourceLink
|
|
4449
|
-
);
|
|
4450
|
-
return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
|
|
4125
|
+
addEmbeddedPortablePdbSourceLink(debugEntryIndex, sourceLink) {
|
|
4126
|
+
return this.#portablePdbEditor.addEmbeddedPortablePdbSourceLink.call(this, debugEntryIndex, sourceLink);
|
|
4451
4127
|
}
|
|
4452
4128
|
|
|
4453
4129
|
replaceFieldSignature(rid, signature) {
|
|
@@ -6141,801 +5817,26 @@ export class Assembly {
|
|
|
6141
5817
|
}
|
|
6142
5818
|
|
|
6143
5819
|
removeMethod(rid) {
|
|
5820
|
+
return this.#methodRemovalEditor.removeMethod.call(this, rid);
|
|
5821
|
+
}
|
|
5822
|
+
|
|
5823
|
+
addParam({ owner, name = "", sequence, flags = 0 }) {
|
|
5824
|
+
return this.#writeParam({ owner, name, sequence, flags }, false).rid;
|
|
5825
|
+
}
|
|
5826
|
+
|
|
5827
|
+
insertParam({ owner, name = "", sequence, flags = 0 }) {
|
|
5828
|
+
return this.#writeParam({ owner, name, sequence, flags }, true);
|
|
5829
|
+
}
|
|
5830
|
+
|
|
5831
|
+
#writeParam({ owner, name = "", sequence, flags = 0 }, insertIntoOwner) {
|
|
6144
5832
|
this.#ensureEditable();
|
|
6145
|
-
|
|
6146
|
-
|
|
5833
|
+
const ownerRid = metadataTableId(owner?.table) === 6 ? owner.rid : 0;
|
|
5834
|
+
const method = this.methods[ownerRid - 1];
|
|
5835
|
+
if (!Number.isInteger(ownerRid) || ownerRid < 1 || !method) {
|
|
5836
|
+
throw new RangeError("Param owner must identify an existing MethodDef");
|
|
6147
5837
|
}
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
);
|
|
6151
|
-
this.#ensureTokenRemappingSafe("MethodDef", {
|
|
6152
|
-
allowEmbeddedPortablePdb: embeddedPdbIndices.length === 1
|
|
6153
|
-
});
|
|
6154
|
-
const rows = this.tables.rows.get(6) ?? [];
|
|
6155
|
-
if (rows.length !== this.tables.counts[6] || rows.length !== this.methods.length) {
|
|
6156
|
-
throw new FormatError("MethodDef row count is inconsistent with the metadata table header");
|
|
6157
|
-
}
|
|
6158
|
-
if (!Number.isInteger(rid) || rid < 1 || rid > rows.length) {
|
|
6159
|
-
throw new RangeError(`Invalid MethodDef row ID ${rid}`);
|
|
6160
|
-
}
|
|
6161
|
-
const cliEntryPointToken = this._cliEntryPointToken ?? this.cli.entryPointToken;
|
|
6162
|
-
const isManagedMethodEntryPoint =
|
|
6163
|
-
(this.cli.flags & 0x10) === 0 &&
|
|
6164
|
-
(cliEntryPointToken >>> 24) === 6;
|
|
6165
|
-
const cliEntryPointRid = cliEntryPointToken & 0x00ffffff;
|
|
6166
|
-
if (isManagedMethodEntryPoint &&
|
|
6167
|
-
(cliEntryPointRid === 0 || cliEntryPointRid > rows.length)) {
|
|
6168
|
-
throw new FormatError("CLI entry point references a missing MethodDef");
|
|
6169
|
-
}
|
|
6170
|
-
if (isManagedMethodEntryPoint && cliEntryPointRid === rid) {
|
|
6171
|
-
throw new FormatError(`MethodDef row ${rid} is the CLI entry point`);
|
|
6172
|
-
}
|
|
6173
|
-
const remappedCliEntryPointToken = isManagedMethodEntryPoint &&
|
|
6174
|
-
cliEntryPointRid > rid
|
|
6175
|
-
? cliEntryPointToken - 1
|
|
6176
|
-
: cliEntryPointToken;
|
|
6177
|
-
const shiftsMethodRids = rid < rows.length;
|
|
6178
|
-
if (shiftsMethodRids && this._addedMethodBodies.size > 0) {
|
|
6179
|
-
throw new UnsupportedFormatError(
|
|
6180
|
-
"MethodDef RID remapping cannot be combined with added method bodies"
|
|
6181
|
-
);
|
|
6182
|
-
}
|
|
6183
|
-
const method = this.methods[rid - 1];
|
|
6184
|
-
if (method?.rid !== rid) throw new FormatError(`MethodDef row ${rid} has inconsistent semantic records`);
|
|
6185
|
-
const genericParamRows = this.tables.rows.get(42) ?? [];
|
|
6186
|
-
if (genericParamRows.length !== (this.tables.counts[42] ?? 0)) {
|
|
6187
|
-
throw new FormatError("GenericParam row count is inconsistent with the metadata table header");
|
|
6188
|
-
}
|
|
6189
|
-
const genericParamRids = new Set(method.genericParams.map((parameter) => parameter.rid));
|
|
6190
|
-
if (genericParamRids.size !== method.genericParams.length ||
|
|
6191
|
-
method.genericParams.length !== this.genericParams.filter(
|
|
6192
|
-
(parameter) => parameter.owner.table === 6 && parameter.owner.rid === rid
|
|
6193
|
-
).length) {
|
|
6194
|
-
throw new FormatError(`MethodDef row ${rid} has inconsistent GenericParam ownership`);
|
|
6195
|
-
}
|
|
6196
|
-
if (genericParamRids.size > 0) {
|
|
6197
|
-
const sortedGenericParamRids = [...genericParamRids].sort((a, b) => a - b);
|
|
6198
|
-
const firstGenericParamRid = sortedGenericParamRids[0];
|
|
6199
|
-
if (firstGenericParamRid < 1 ||
|
|
6200
|
-
sortedGenericParamRids.some((parameterRid, index) =>
|
|
6201
|
-
parameterRid !== firstGenericParamRid + index
|
|
6202
|
-
) || sortedGenericParamRids.at(-1) > genericParamRows.length) {
|
|
6203
|
-
throw new UnsupportedFormatError(
|
|
6204
|
-
"MethodDef removal requires its GenericParam rows to form a contiguous table range"
|
|
6205
|
-
);
|
|
6206
|
-
}
|
|
6207
|
-
}
|
|
6208
|
-
const genericParamConstraintRows = this.tables.rows.get(44) ?? [];
|
|
6209
|
-
if (genericParamConstraintRows.length !== (this.tables.counts[44] ?? 0) ||
|
|
6210
|
-
genericParamConstraintRows.length !== this.genericParamConstraints.length) {
|
|
6211
|
-
throw new FormatError("GenericParamConstraint row count is inconsistent with the metadata table header");
|
|
6212
|
-
}
|
|
6213
|
-
const genericParamConstraintRids = new Set(
|
|
6214
|
-
this.genericParamConstraints
|
|
6215
|
-
.filter((constraint) => genericParamRids.has(constraint.ownerRid))
|
|
6216
|
-
.map((constraint) => constraint.rid)
|
|
6217
|
-
);
|
|
6218
|
-
if (genericParamConstraintRids.size > 0) {
|
|
6219
|
-
for (const [tableId, tableRows] of this.tables.rows) {
|
|
6220
|
-
const schema = metadataTableSchemas[tableId];
|
|
6221
|
-
if (!schema) {
|
|
6222
|
-
throw new UnsupportedFormatError(
|
|
6223
|
-
`Cannot remove MethodDef row ${rid} with unknown metadata table ${tableId}`
|
|
6224
|
-
);
|
|
6225
|
-
}
|
|
6226
|
-
for (const row of tableRows) {
|
|
6227
|
-
if (tableId === 44 && genericParamConstraintRids.has(row.rid)) continue;
|
|
6228
|
-
for (const [kind, value, name] of schema) {
|
|
6229
|
-
const columnName = name ?? value;
|
|
6230
|
-
const column = row[columnName];
|
|
6231
|
-
const target = kind === "coded"
|
|
6232
|
-
? column?.target
|
|
6233
|
-
: kind === "table" ? { table: value, rid: column?.rid } : null;
|
|
6234
|
-
if (target?.table === 44 && genericParamConstraintRids.has(target.rid)) {
|
|
6235
|
-
throw new FormatError(
|
|
6236
|
-
`GenericParamConstraint row ${target.rid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
|
|
6237
|
-
);
|
|
6238
|
-
}
|
|
6239
|
-
if (kind === "u4" && (tableId === 30 || tableId === 31) &&
|
|
6240
|
-
columnName === "Token" && row[columnName] >>> 24 === 44 &&
|
|
6241
|
-
genericParamConstraintRids.has(row[columnName] & 0x00ffffff)) {
|
|
6242
|
-
throw new FormatError(
|
|
6243
|
-
`GenericParamConstraint row ${row[columnName] & 0x00ffffff} is referenced by ${metadataTableNames[tableId]}.${columnName}`
|
|
6244
|
-
);
|
|
6245
|
-
}
|
|
6246
|
-
}
|
|
6247
|
-
}
|
|
6248
|
-
}
|
|
6249
|
-
for (const candidate of this.methods) {
|
|
6250
|
-
for (const instruction of this.getMethodBody(candidate.rid)?.instructions ?? []) {
|
|
6251
|
-
const token = instruction.operand?.kind === "token" ? instruction.operand.value : 0;
|
|
6252
|
-
if ((token >>> 24) === 44 && genericParamConstraintRids.has(token & 0x00ffffff)) {
|
|
6253
|
-
throw new FormatError(
|
|
6254
|
-
`GenericParamConstraint row ${token & 0x00ffffff} is referenced by CIL in MethodDef row ${candidate.rid}`
|
|
6255
|
-
);
|
|
6256
|
-
}
|
|
6257
|
-
}
|
|
6258
|
-
}
|
|
6259
|
-
}
|
|
6260
|
-
const parameterRows = this.tables.rows.get(8) ?? [];
|
|
6261
|
-
if (parameterRows.length !== (this.tables.counts[8] ?? 0)) {
|
|
6262
|
-
throw new FormatError("Param row count is inconsistent with the metadata table header");
|
|
6263
|
-
}
|
|
6264
|
-
const parameterRids = new Set(method.parameterRids);
|
|
6265
|
-
if (method.parameterRids.length !== method.parameters.length ||
|
|
6266
|
-
parameterRids.size !== method.parameterRids.length) {
|
|
6267
|
-
throw new FormatError(`MethodDef row ${rid} has inconsistent Param ownership`);
|
|
6268
|
-
}
|
|
6269
|
-
if (parameterRids.size > 0) {
|
|
6270
|
-
const sortedParameterRids = [...parameterRids].sort((a, b) => a - b);
|
|
6271
|
-
const firstParameterRid = sortedParameterRids[0];
|
|
6272
|
-
if (firstParameterRid < 1 ||
|
|
6273
|
-
sortedParameterRids.some((parameterRid, index) => parameterRid !== firstParameterRid + index) ||
|
|
6274
|
-
sortedParameterRids.at(-1) > parameterRows.length) {
|
|
6275
|
-
throw new UnsupportedFormatError(
|
|
6276
|
-
"MethodDef removal requires its Param rows to form a contiguous table range"
|
|
6277
|
-
);
|
|
6278
|
-
}
|
|
6279
|
-
}
|
|
6280
|
-
const owners = this.types.filter((type) => type.methodRids.includes(rid));
|
|
6281
|
-
if (owners.length !== 1 || !owners[0].methods.some((candidate) => candidate.rid === rid)) {
|
|
6282
|
-
throw new FormatError(`MethodDef row ${rid} has no unique resolved TypeDef owner`);
|
|
6283
|
-
}
|
|
6284
|
-
const supportedStreams = new Set(["#~", "#-", "#Strings", "#US", "#GUID", "#Blob"]);
|
|
6285
|
-
for (const streamName of this.metadataRoot.streams.keys()) {
|
|
6286
|
-
if (!supportedStreams.has(streamName)) {
|
|
6287
|
-
throw new UnsupportedFormatError(
|
|
6288
|
-
`Cannot remove MethodDef row ${rid} with unrecognized metadata stream ${streamName}`
|
|
6289
|
-
);
|
|
6290
|
-
}
|
|
6291
|
-
}
|
|
6292
|
-
|
|
6293
|
-
const paramPointerRows = parameterRids.size > 0
|
|
6294
|
-
? getBijectivePointerRows(this, 7, 8, "Param")
|
|
6295
|
-
: null;
|
|
6296
|
-
if (parameterRids.size > 0 && (this.tables.valid & (1n << 7n)) !== 0n) {
|
|
6297
|
-
const pointerRids = paramPointerRows
|
|
6298
|
-
.filter((pointer) => parameterRids.has(pointer.Param.rid))
|
|
6299
|
-
.map((pointer) => pointer.rid);
|
|
6300
|
-
const firstPointerRid = Math.min(...pointerRids);
|
|
6301
|
-
if (pointerRids.length !== parameterRids.size ||
|
|
6302
|
-
[...pointerRids].sort((a, b) => a - b)
|
|
6303
|
-
.some((pointerRid, index) => pointerRid !== firstPointerRid + index)) {
|
|
6304
|
-
throw new UnsupportedFormatError(
|
|
6305
|
-
"MethodDef removal requires its ParamPtr rows to form a contiguous pointer range"
|
|
6306
|
-
);
|
|
6307
|
-
}
|
|
6308
|
-
}
|
|
6309
|
-
if (parameterRids.size > 0) {
|
|
6310
|
-
for (const [tableId, tableRows] of this.tables.rows) {
|
|
6311
|
-
const schema = metadataTableSchemas[tableId];
|
|
6312
|
-
if (!schema) {
|
|
6313
|
-
throw new UnsupportedFormatError(
|
|
6314
|
-
`Cannot remove MethodDef row ${rid} with unknown metadata table ${tableId}`
|
|
6315
|
-
);
|
|
6316
|
-
}
|
|
6317
|
-
for (const row of tableRows) {
|
|
6318
|
-
for (const [kind, value, name, pointer] of schema) {
|
|
6319
|
-
const columnName = name ?? value;
|
|
6320
|
-
if (kind === "coded" && row[columnName]?.target?.table === 8 &&
|
|
6321
|
-
parameterRids.has(row[columnName].target.rid)) {
|
|
6322
|
-
throw new FormatError(
|
|
6323
|
-
`Param row ${row[columnName].target.rid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
|
|
6324
|
-
);
|
|
6325
|
-
}
|
|
6326
|
-
if (kind === "table") {
|
|
6327
|
-
const targetTable = pointer !== undefined &&
|
|
6328
|
-
(this.tables.valid & (1n << BigInt(pointer))) !== 0n ? pointer : value;
|
|
6329
|
-
if (targetTable !== 8 || (tableId === 6 && columnName === "ParamList") ||
|
|
6330
|
-
(tableId === 7 && columnName === "Param")) continue;
|
|
6331
|
-
if (parameterRids.has(row[columnName]?.rid)) {
|
|
6332
|
-
throw new FormatError(
|
|
6333
|
-
`Param row ${row[columnName].rid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
|
|
6334
|
-
);
|
|
6335
|
-
}
|
|
6336
|
-
}
|
|
6337
|
-
if (kind === "u4" && (tableId === 30 || tableId === 31) &&
|
|
6338
|
-
columnName === "Token" && row[columnName] >>> 24 === 8 &&
|
|
6339
|
-
parameterRids.has(row[columnName] & 0x00ffffff)) {
|
|
6340
|
-
throw new FormatError(
|
|
6341
|
-
`Param row ${row[columnName] & 0x00ffffff} is referenced by ${metadataTableNames[tableId]}.${columnName}`
|
|
6342
|
-
);
|
|
6343
|
-
}
|
|
6344
|
-
}
|
|
6345
|
-
}
|
|
6346
|
-
}
|
|
6347
|
-
}
|
|
6348
|
-
if (genericParamRids.size > 0) {
|
|
6349
|
-
for (const [tableId, tableRows] of this.tables.rows) {
|
|
6350
|
-
const schema = metadataTableSchemas[tableId];
|
|
6351
|
-
if (!schema) {
|
|
6352
|
-
throw new UnsupportedFormatError(
|
|
6353
|
-
`Cannot remove MethodDef row ${rid} with unknown metadata table ${tableId}`
|
|
6354
|
-
);
|
|
6355
|
-
}
|
|
6356
|
-
for (const row of tableRows) {
|
|
6357
|
-
if (tableId === 44 && genericParamConstraintRids.has(row.rid)) continue;
|
|
6358
|
-
for (const [kind, value, name] of schema) {
|
|
6359
|
-
const columnName = name ?? value;
|
|
6360
|
-
const column = row[columnName];
|
|
6361
|
-
const target = kind === "coded"
|
|
6362
|
-
? column?.target
|
|
6363
|
-
: kind === "table" ? { table: value, rid: column?.rid } : null;
|
|
6364
|
-
if (target?.table === 42 && genericParamRids.has(target.rid)) {
|
|
6365
|
-
throw new FormatError(
|
|
6366
|
-
`GenericParam row ${target.rid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
|
|
6367
|
-
);
|
|
6368
|
-
}
|
|
6369
|
-
if (kind === "u4" && (tableId === 30 || tableId === 31) &&
|
|
6370
|
-
columnName === "Token" && row[columnName] >>> 24 === 42 &&
|
|
6371
|
-
genericParamRids.has(row[columnName] & 0x00ffffff)) {
|
|
6372
|
-
throw new FormatError(
|
|
6373
|
-
`GenericParam row ${row[columnName] & 0x00ffffff} is referenced by ${metadataTableNames[tableId]}.${columnName}`
|
|
6374
|
-
);
|
|
6375
|
-
}
|
|
6376
|
-
}
|
|
6377
|
-
}
|
|
6378
|
-
}
|
|
6379
|
-
}
|
|
6380
|
-
|
|
6381
|
-
const pointerRows = getBijectivePointerRows(this, 5, 6, "Method");
|
|
6382
|
-
const pointerRid = pointerRows
|
|
6383
|
-
? pointerRows.findIndex((pointer) => pointer.Method.rid === rid) + 1
|
|
6384
|
-
: 0;
|
|
6385
|
-
if (pointerRows && pointerRid === 0) {
|
|
6386
|
-
throw new FormatError(`MethodPtr has no pointer to MethodDef row ${rid}`);
|
|
6387
|
-
}
|
|
6388
|
-
const tokenMap = new Map();
|
|
6389
|
-
for (let oldRid = rid + 1; oldRid <= rows.length; oldRid++) {
|
|
6390
|
-
tokenMap.set(0x06000000 + oldRid, 0x06000000 + oldRid - 1);
|
|
6391
|
-
}
|
|
6392
|
-
const lastParameterRid = parameterRids.size > 0
|
|
6393
|
-
? Math.max(...parameterRids)
|
|
6394
|
-
: 0;
|
|
6395
|
-
const remapParameterRid = (oldRid) =>
|
|
6396
|
-
oldRid > lastParameterRid ? oldRid - parameterRids.size : oldRid;
|
|
6397
|
-
if (parameterRids.size > 0) {
|
|
6398
|
-
for (let oldRid = lastParameterRid + 1; oldRid <= parameterRows.length; oldRid++) {
|
|
6399
|
-
tokenMap.set(0x08000000 + oldRid, 0x08000000 + remapParameterRid(oldRid));
|
|
6400
|
-
}
|
|
6401
|
-
}
|
|
6402
|
-
const lastGenericParamRid = genericParamRids.size > 0
|
|
6403
|
-
? Math.max(...genericParamRids)
|
|
6404
|
-
: 0;
|
|
6405
|
-
const remapGenericParamRid = (oldRid) =>
|
|
6406
|
-
oldRid > lastGenericParamRid ? oldRid - genericParamRids.size : oldRid;
|
|
6407
|
-
if (genericParamRids.size > 0) {
|
|
6408
|
-
for (let oldRid = lastGenericParamRid + 1; oldRid <= genericParamRows.length; oldRid++) {
|
|
6409
|
-
tokenMap.set(0x2a000000 + oldRid, 0x2a000000 + remapGenericParamRid(oldRid));
|
|
6410
|
-
}
|
|
6411
|
-
}
|
|
6412
|
-
const remapGenericParamConstraintRid = (oldRid) => oldRid -
|
|
6413
|
-
[...genericParamConstraintRids].filter((constraintRid) => constraintRid < oldRid).length;
|
|
6414
|
-
if (genericParamConstraintRids.size > 0) {
|
|
6415
|
-
for (let oldRid = 1; oldRid <= genericParamConstraintRows.length; oldRid++) {
|
|
6416
|
-
if (genericParamConstraintRids.has(oldRid)) continue;
|
|
6417
|
-
tokenMap.set(
|
|
6418
|
-
0x2c000000 + oldRid,
|
|
6419
|
-
0x2c000000 + remapGenericParamConstraintRid(oldRid)
|
|
6420
|
-
);
|
|
6421
|
-
}
|
|
6422
|
-
}
|
|
6423
|
-
const rowChanges = [];
|
|
6424
|
-
for (const [tableId, tableRows] of this.tables.rows) {
|
|
6425
|
-
const schema = metadataTableSchemas[tableId];
|
|
6426
|
-
if (!schema) {
|
|
6427
|
-
throw new UnsupportedFormatError(
|
|
6428
|
-
`Cannot remove MethodDef row ${rid} with unknown metadata table ${tableId}`
|
|
6429
|
-
);
|
|
6430
|
-
}
|
|
6431
|
-
for (const row of tableRows) {
|
|
6432
|
-
if (tableId === 44 && genericParamConstraintRids.has(row.rid)) continue;
|
|
6433
|
-
for (const [kind, value, name, pointer] of schema) {
|
|
6434
|
-
const columnName = name ?? value;
|
|
6435
|
-
if (kind === "coded") {
|
|
6436
|
-
const target = row[columnName]?.target;
|
|
6437
|
-
if (target?.table === 44) {
|
|
6438
|
-
if (genericParamConstraintRids.has(target.rid)) {
|
|
6439
|
-
throw new FormatError(
|
|
6440
|
-
`GenericParamConstraint row ${target.rid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
|
|
6441
|
-
);
|
|
6442
|
-
}
|
|
6443
|
-
const remappedRid = remapGenericParamConstraintRid(target.rid);
|
|
6444
|
-
if (remappedRid !== target.rid) {
|
|
6445
|
-
const remappedTarget = { ...target, rid: remappedRid };
|
|
6446
|
-
rowChanges.push({
|
|
6447
|
-
row,
|
|
6448
|
-
columnName,
|
|
6449
|
-
value: {
|
|
6450
|
-
raw: encodeCodedIndex(44, remappedRid, value),
|
|
6451
|
-
target: remappedTarget
|
|
6452
|
-
}
|
|
6453
|
-
});
|
|
6454
|
-
}
|
|
6455
|
-
continue;
|
|
6456
|
-
}
|
|
6457
|
-
if (target?.table === 8 || target?.table === 42) {
|
|
6458
|
-
const removedRids = target.table === 8 ? parameterRids : genericParamRids;
|
|
6459
|
-
if (removedRids.has(target.rid)) {
|
|
6460
|
-
throw new FormatError(
|
|
6461
|
-
`${metadataTableNames[target.table]} row ${target.rid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
|
|
6462
|
-
);
|
|
6463
|
-
}
|
|
6464
|
-
const remappedRid = target.table === 8
|
|
6465
|
-
? remapParameterRid(target.rid)
|
|
6466
|
-
: remapGenericParamRid(target.rid);
|
|
6467
|
-
if (remappedRid !== target.rid) {
|
|
6468
|
-
const remappedTarget = { ...target, rid: remappedRid };
|
|
6469
|
-
rowChanges.push({
|
|
6470
|
-
row,
|
|
6471
|
-
columnName,
|
|
6472
|
-
value: {
|
|
6473
|
-
raw: encodeCodedIndex(target.table, remappedRid, value),
|
|
6474
|
-
target: remappedTarget
|
|
6475
|
-
}
|
|
6476
|
-
});
|
|
6477
|
-
}
|
|
6478
|
-
continue;
|
|
6479
|
-
}
|
|
6480
|
-
if (target?.table !== 6) continue;
|
|
6481
|
-
if (tableId === 42 && columnName === "Owner" &&
|
|
6482
|
-
genericParamRids.has(row.rid)) continue;
|
|
6483
|
-
if (target.rid === rid) {
|
|
6484
|
-
throw new FormatError(`MethodDef row ${rid} is referenced by ${metadataTableNames[tableId]}.${columnName}`);
|
|
6485
|
-
}
|
|
6486
|
-
if (target.rid > rid) {
|
|
6487
|
-
const remappedTarget = { ...target, rid: target.rid - 1 };
|
|
6488
|
-
rowChanges.push({
|
|
6489
|
-
row,
|
|
6490
|
-
columnName,
|
|
6491
|
-
value: {
|
|
6492
|
-
raw: encodeCodedIndex(6, remappedTarget.rid, value),
|
|
6493
|
-
target: remappedTarget
|
|
6494
|
-
}
|
|
6495
|
-
});
|
|
6496
|
-
}
|
|
6497
|
-
} else if (kind === "u4" && (tableId === 30 || tableId === 31) &&
|
|
6498
|
-
columnName === "Token" && [8, 42].includes(row[columnName] >>> 24)) {
|
|
6499
|
-
const tokenTable = row[columnName] >>> 24;
|
|
6500
|
-
const targetRid = row[columnName] & 0x00ffffff;
|
|
6501
|
-
const removedRids = tokenTable === 8 ? parameterRids : genericParamRids;
|
|
6502
|
-
if (removedRids.has(targetRid)) {
|
|
6503
|
-
throw new FormatError(
|
|
6504
|
-
`${metadataTableNames[tokenTable]} row ${targetRid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
|
|
6505
|
-
);
|
|
6506
|
-
}
|
|
6507
|
-
const remappedRid = tokenTable === 8
|
|
6508
|
-
? remapParameterRid(targetRid)
|
|
6509
|
-
: remapGenericParamRid(targetRid);
|
|
6510
|
-
if (remappedRid !== targetRid) {
|
|
6511
|
-
rowChanges.push({
|
|
6512
|
-
row,
|
|
6513
|
-
columnName,
|
|
6514
|
-
value: (tokenTable << 24) | remappedRid
|
|
6515
|
-
});
|
|
6516
|
-
}
|
|
6517
|
-
} else if (kind === "u4" && (tableId === 30 || tableId === 31) &&
|
|
6518
|
-
columnName === "Token" && row[columnName] >>> 24 === 44) {
|
|
6519
|
-
const targetRid = row[columnName] & 0x00ffffff;
|
|
6520
|
-
if (genericParamConstraintRids.has(targetRid)) {
|
|
6521
|
-
throw new FormatError(
|
|
6522
|
-
`GenericParamConstraint row ${targetRid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
|
|
6523
|
-
);
|
|
6524
|
-
}
|
|
6525
|
-
const remappedRid = remapGenericParamConstraintRid(targetRid);
|
|
6526
|
-
if (remappedRid !== targetRid) {
|
|
6527
|
-
rowChanges.push({
|
|
6528
|
-
row,
|
|
6529
|
-
columnName,
|
|
6530
|
-
value: 0x2c000000 | remappedRid
|
|
6531
|
-
});
|
|
6532
|
-
}
|
|
6533
|
-
} else if (kind === "u4" && (tableId === 30 || tableId === 31) &&
|
|
6534
|
-
columnName === "Token" && row[columnName] >>> 24 === 6 &&
|
|
6535
|
-
(row[columnName] & 0x00ffffff) === rid) {
|
|
6536
|
-
throw new FormatError(`MethodDef row ${rid} is referenced by ${metadataTableNames[tableId]}.${columnName}`);
|
|
6537
|
-
} else if (kind === "u4" && (tableId === 30 || tableId === 31) &&
|
|
6538
|
-
columnName === "Token" && row[columnName] >>> 24 === 6 &&
|
|
6539
|
-
(row[columnName] & 0x00ffffff) > rid) {
|
|
6540
|
-
const oldToken = row[columnName];
|
|
6541
|
-
rowChanges.push({ row, columnName, value: oldToken - 1 });
|
|
6542
|
-
} else if (kind === "table") {
|
|
6543
|
-
if (tableId === 2 && columnName === "MethodList") continue;
|
|
6544
|
-
const targetTable = pointer !== undefined &&
|
|
6545
|
-
(this.tables.valid & (1n << BigInt(pointer))) !== 0n ? pointer : value;
|
|
6546
|
-
const targetRid = row[columnName]?.rid;
|
|
6547
|
-
if (targetTable === 8) {
|
|
6548
|
-
if ((tableId === 6 && columnName === "ParamList") ||
|
|
6549
|
-
(tableId === 7 && columnName === "Param")) continue;
|
|
6550
|
-
if (parameterRids.has(targetRid)) {
|
|
6551
|
-
throw new FormatError(
|
|
6552
|
-
`Param row ${targetRid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
|
|
6553
|
-
);
|
|
6554
|
-
}
|
|
6555
|
-
const remappedRid = remapParameterRid(targetRid);
|
|
6556
|
-
if (remappedRid !== targetRid) {
|
|
6557
|
-
rowChanges.push({
|
|
6558
|
-
row,
|
|
6559
|
-
columnName,
|
|
6560
|
-
value: { ...row[columnName], raw: remappedRid, rid: remappedRid }
|
|
6561
|
-
});
|
|
6562
|
-
}
|
|
6563
|
-
continue;
|
|
6564
|
-
}
|
|
6565
|
-
if (targetTable === 42) {
|
|
6566
|
-
if (genericParamRids.has(targetRid)) {
|
|
6567
|
-
throw new FormatError(
|
|
6568
|
-
`GenericParam row ${targetRid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
|
|
6569
|
-
);
|
|
6570
|
-
}
|
|
6571
|
-
const remappedRid = remapGenericParamRid(targetRid);
|
|
6572
|
-
if (remappedRid !== targetRid) {
|
|
6573
|
-
rowChanges.push({
|
|
6574
|
-
row,
|
|
6575
|
-
columnName,
|
|
6576
|
-
value: { ...row[columnName], raw: remappedRid, rid: remappedRid }
|
|
6577
|
-
});
|
|
6578
|
-
}
|
|
6579
|
-
continue;
|
|
6580
|
-
}
|
|
6581
|
-
if (targetTable === 44) {
|
|
6582
|
-
if (genericParamConstraintRids.has(targetRid)) {
|
|
6583
|
-
throw new FormatError(
|
|
6584
|
-
`GenericParamConstraint row ${targetRid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
|
|
6585
|
-
);
|
|
6586
|
-
}
|
|
6587
|
-
const remappedRid = remapGenericParamConstraintRid(targetRid);
|
|
6588
|
-
if (remappedRid !== targetRid) {
|
|
6589
|
-
rowChanges.push({
|
|
6590
|
-
row,
|
|
6591
|
-
columnName,
|
|
6592
|
-
value: { ...row[columnName], raw: remappedRid, rid: remappedRid }
|
|
6593
|
-
});
|
|
6594
|
-
}
|
|
6595
|
-
continue;
|
|
6596
|
-
}
|
|
6597
|
-
if (targetTable !== 6) continue;
|
|
6598
|
-
if (tableId === 5 && columnName === "Method") {
|
|
6599
|
-
if (row.rid === pointerRid) continue;
|
|
6600
|
-
if (targetRid === rid) {
|
|
6601
|
-
throw new FormatError(`MethodDef row ${rid} is referenced by MethodPtr.Method`);
|
|
6602
|
-
}
|
|
6603
|
-
continue;
|
|
6604
|
-
}
|
|
6605
|
-
if (targetRid === rid) {
|
|
6606
|
-
throw new FormatError(`MethodDef row ${rid} is referenced by ${metadataTableNames[tableId]}.${columnName}`);
|
|
6607
|
-
}
|
|
6608
|
-
if (targetRid > rid) {
|
|
6609
|
-
rowChanges.push({
|
|
6610
|
-
row,
|
|
6611
|
-
columnName,
|
|
6612
|
-
value: { ...row[columnName], raw: targetRid - 1, rid: targetRid - 1 }
|
|
6613
|
-
});
|
|
6614
|
-
}
|
|
6615
|
-
}
|
|
6616
|
-
}
|
|
6617
|
-
}
|
|
6618
|
-
}
|
|
6619
|
-
const tokenUpdates = [];
|
|
6620
|
-
const patches = [];
|
|
6621
|
-
for (const candidate of this.methods) {
|
|
6622
|
-
if (candidate.rid === rid) continue;
|
|
6623
|
-
const body = this.getMethodBody(candidate.rid);
|
|
6624
|
-
for (const instruction of body?.instructions ?? []) {
|
|
6625
|
-
const token = instruction.operand?.kind === "token" ? instruction.operand.value : 0;
|
|
6626
|
-
if ((token >>> 24) !== 6) continue;
|
|
6627
|
-
const targetRid = token & 0x00ffffff;
|
|
6628
|
-
if (targetRid === rid) {
|
|
6629
|
-
throw new FormatError(`MethodDef row ${rid} is referenced by CIL in MethodDef row ${candidate.rid}`);
|
|
6630
|
-
}
|
|
6631
|
-
if (targetRid > rid) {
|
|
6632
|
-
const replacement = token - 1;
|
|
6633
|
-
tokenUpdates.push({ instruction, replacement });
|
|
6634
|
-
patches.push(...createOperandPatches(instruction, replacement));
|
|
6635
|
-
}
|
|
6636
|
-
}
|
|
6637
|
-
}
|
|
6638
|
-
const sortedKeyColumns = new Map([
|
|
6639
|
-
[10, "Class"], [11, "Parent"], [12, "Parent"], [13, "Parent"], [14, "Parent"],
|
|
6640
|
-
[28, "MemberForwarded"], [42, "Owner"], [43, "Method"]
|
|
6641
|
-
]);
|
|
6642
|
-
const changedSortedKeys = new Map(rowChanges
|
|
6643
|
-
.filter((change) => [...sortedKeyColumns.values()].includes(change.columnName))
|
|
6644
|
-
.map((change) => [change.row, change.value]));
|
|
6645
|
-
for (const [tableId, keyOf] of [
|
|
6646
|
-
[10, (row) => [row.Class.raw]],
|
|
6647
|
-
[11, (row) => [row.Parent.raw]],
|
|
6648
|
-
[12, (row) => [row.Parent.raw]],
|
|
6649
|
-
[13, (row) => [row.Parent.raw]],
|
|
6650
|
-
[14, (row) => [row.Parent.raw, row.Action]],
|
|
6651
|
-
[28, (row) => [row.MemberForwarded.raw]],
|
|
6652
|
-
[42, (row) => [row.Owner.raw, row.Number]],
|
|
6653
|
-
[43, (row) => [row.Method.raw]]
|
|
6654
|
-
]) {
|
|
6655
|
-
if ((this.tables.sorted & (1n << BigInt(tableId))) === 0n) continue;
|
|
6656
|
-
let previous = null;
|
|
6657
|
-
for (const row of this.tables.get(tableId)) {
|
|
6658
|
-
const changedKey = changedSortedKeys.get(row);
|
|
6659
|
-
const current = keyOf(row);
|
|
6660
|
-
if (changedKey) current[0] = changedKey.raw ?? changedKey;
|
|
6661
|
-
let outOfOrder = false;
|
|
6662
|
-
if (previous) {
|
|
6663
|
-
for (let index = 0; index < current.length; index++) {
|
|
6664
|
-
if (current[index] === previous[index]) continue;
|
|
6665
|
-
outOfOrder = current[index] < previous[index];
|
|
6666
|
-
break;
|
|
6667
|
-
}
|
|
6668
|
-
}
|
|
6669
|
-
if (outOfOrder) {
|
|
6670
|
-
throw new FormatError(
|
|
6671
|
-
`MethodDef token remapping would violate sorted ${metadataTableNames[tableId]} order`
|
|
6672
|
-
);
|
|
6673
|
-
}
|
|
6674
|
-
previous = current;
|
|
6675
|
-
}
|
|
6676
|
-
}
|
|
6677
|
-
|
|
6678
|
-
const methodPointerPresent = pointerRows !== null;
|
|
6679
|
-
if (embeddedPdbIndices.length === 1) {
|
|
6680
|
-
const updatedCounts = [...this.tables.counts];
|
|
6681
|
-
updatedCounts[6]--;
|
|
6682
|
-
if (methodPointerPresent) updatedCounts[5]--;
|
|
6683
|
-
if (parameterRids.size > 0) {
|
|
6684
|
-
updatedCounts[8] -= parameterRids.size;
|
|
6685
|
-
if (paramPointerRows) updatedCounts[7] -= parameterRids.size;
|
|
6686
|
-
}
|
|
6687
|
-
if (genericParamRids.size > 0) updatedCounts[42] -= genericParamRids.size;
|
|
6688
|
-
if (genericParamConstraintRids.size > 0) {
|
|
6689
|
-
updatedCounts[44] -= genericParamConstraintRids.size;
|
|
6690
|
-
}
|
|
6691
|
-
const debugEntryIndex = embeddedPdbIndices[0];
|
|
6692
|
-
const debugEntry = this.pe.debugDirectoryEntries[debugEntryIndex];
|
|
6693
|
-
const pdb = this.#getPortablePdbForEdit(debugEntryIndex, debugEntry);
|
|
6694
|
-
const updatedPdb = removePortablePdbMethod(
|
|
6695
|
-
pdb,
|
|
6696
|
-
rid,
|
|
6697
|
-
this.tables.counts,
|
|
6698
|
-
updatedCounts
|
|
6699
|
-
);
|
|
6700
|
-
this.#replaceEmbeddedPortablePdb(debugEntryIndex, updatedPdb, updatedCounts);
|
|
6701
|
-
}
|
|
6702
|
-
if (remappedCliEntryPointToken !== cliEntryPointToken) {
|
|
6703
|
-
const entryPointBytes = new Uint8Array(4);
|
|
6704
|
-
new DataView(entryPointBytes.buffer).setUint32(0, remappedCliEntryPointToken, true);
|
|
6705
|
-
patches.push({
|
|
6706
|
-
offset: this.cli.offset + 20,
|
|
6707
|
-
bytes: entryPointBytes
|
|
6708
|
-
});
|
|
6709
|
-
this._cliEntryPointToken = remappedCliEntryPointToken;
|
|
6710
|
-
}
|
|
6711
|
-
if (methodPointerPresent) {
|
|
6712
|
-
const remainingPointers = pointerRows.filter((pointer) => pointer.rid !== pointerRid);
|
|
6713
|
-
remainingPointers.forEach((pointer, index) => {
|
|
6714
|
-
pointer.rid = index + 1;
|
|
6715
|
-
if (pointer.Method.rid > rid) {
|
|
6716
|
-
pointer.Method = {
|
|
6717
|
-
...pointer.Method,
|
|
6718
|
-
raw: pointer.Method.rid - 1,
|
|
6719
|
-
rid: pointer.Method.rid - 1
|
|
6720
|
-
};
|
|
6721
|
-
}
|
|
6722
|
-
});
|
|
6723
|
-
this.tables.rows.set(5, remainingPointers);
|
|
6724
|
-
this.tables.counts[5] = remainingPointers.length;
|
|
6725
|
-
if (remainingPointers.length === 0) this.tables.valid &= ~(1n << 5n);
|
|
6726
|
-
}
|
|
6727
|
-
const listBoundary = methodPointerPresent ? pointerRid : rid;
|
|
6728
|
-
const listChanges = [];
|
|
6729
|
-
for (const typeRow of this.tables.rows.get(2) ?? []) {
|
|
6730
|
-
if (typeRow.MethodList.rid > listBoundary) {
|
|
6731
|
-
listChanges.push({
|
|
6732
|
-
row: typeRow,
|
|
6733
|
-
value: {
|
|
6734
|
-
...typeRow.MethodList,
|
|
6735
|
-
raw: typeRow.MethodList.rid - 1,
|
|
6736
|
-
rid: typeRow.MethodList.rid - 1
|
|
6737
|
-
}
|
|
6738
|
-
});
|
|
6739
|
-
}
|
|
6740
|
-
}
|
|
6741
|
-
const removedParamListPositions = paramPointerRows
|
|
6742
|
-
? paramPointerRows.filter((pointer) => parameterRids.has(pointer.Param.rid))
|
|
6743
|
-
.map((pointer) => pointer.rid)
|
|
6744
|
-
: [...parameterRids];
|
|
6745
|
-
const paramListChanges = [];
|
|
6746
|
-
if (removedParamListPositions.length > 0) {
|
|
6747
|
-
for (const methodRow of this.tables.get(6)) {
|
|
6748
|
-
const oldBoundary = methodRow.ParamList.rid;
|
|
6749
|
-
const newBoundary = oldBoundary -
|
|
6750
|
-
removedParamListPositions.filter((position) => position < oldBoundary).length;
|
|
6751
|
-
if (newBoundary === oldBoundary) continue;
|
|
6752
|
-
paramListChanges.push({
|
|
6753
|
-
row: methodRow,
|
|
6754
|
-
value: {
|
|
6755
|
-
...methodRow.ParamList,
|
|
6756
|
-
raw: newBoundary,
|
|
6757
|
-
rid: newBoundary
|
|
6758
|
-
}
|
|
6759
|
-
});
|
|
6760
|
-
}
|
|
6761
|
-
}
|
|
6762
|
-
for (const change of rowChanges) change.row[change.columnName] = change.value;
|
|
6763
|
-
for (const change of listChanges) change.row.MethodList = change.value;
|
|
6764
|
-
for (const change of paramListChanges) change.row.ParamList = change.value;
|
|
6765
|
-
for (const update of tokenUpdates) update.instruction.operand.value = update.replacement;
|
|
6766
|
-
this._patches.push(...patches);
|
|
6767
|
-
if (parameterRids.size > 0) {
|
|
6768
|
-
const remainingParams = parameterRows.filter((parameter) => !parameterRids.has(parameter.rid));
|
|
6769
|
-
remainingParams.forEach((parameter) => {
|
|
6770
|
-
parameter.rid = remapParameterRid(parameter.rid);
|
|
6771
|
-
});
|
|
6772
|
-
this.tables.rows.set(8, remainingParams);
|
|
6773
|
-
this.tables.counts[8] = remainingParams.length;
|
|
6774
|
-
if (remainingParams.length === 0) this.tables.valid &= ~(1n << 8n);
|
|
6775
|
-
if (paramPointerRows) {
|
|
6776
|
-
const remainingParamPointers = paramPointerRows.filter((pointer) =>
|
|
6777
|
-
!parameterRids.has(pointer.Param.rid)
|
|
6778
|
-
);
|
|
6779
|
-
remainingParamPointers.forEach((pointer, index) => {
|
|
6780
|
-
pointer.rid = index + 1;
|
|
6781
|
-
const remappedRid = remapParameterRid(pointer.Param.rid);
|
|
6782
|
-
if (remappedRid !== pointer.Param.rid) {
|
|
6783
|
-
pointer.Param = {
|
|
6784
|
-
...pointer.Param,
|
|
6785
|
-
raw: remappedRid,
|
|
6786
|
-
rid: remappedRid
|
|
6787
|
-
};
|
|
6788
|
-
}
|
|
6789
|
-
});
|
|
6790
|
-
this.tables.rows.set(7, remainingParamPointers);
|
|
6791
|
-
this.tables.counts[7] = remainingParamPointers.length;
|
|
6792
|
-
if (remainingParamPointers.length === 0) this.tables.valid &= ~(1n << 7n);
|
|
6793
|
-
}
|
|
6794
|
-
for (const candidate of this.methods) {
|
|
6795
|
-
candidate.parameterRids = candidate.parameterRids
|
|
6796
|
-
.filter((parameterRid) => !parameterRids.has(parameterRid))
|
|
6797
|
-
.map(remapParameterRid);
|
|
6798
|
-
candidate.parameters = candidate.parameters
|
|
6799
|
-
.filter((parameter) => !parameterRids.has(parameter.rid))
|
|
6800
|
-
.map((parameter) => {
|
|
6801
|
-
parameter.rid = remapParameterRid(parameter.rid);
|
|
6802
|
-
return parameter;
|
|
6803
|
-
});
|
|
6804
|
-
}
|
|
6805
|
-
}
|
|
6806
|
-
if (genericParamRids.size > 0) {
|
|
6807
|
-
const remainingGenericParams = genericParamRows.filter((parameter) =>
|
|
6808
|
-
!genericParamRids.has(parameter.rid)
|
|
6809
|
-
);
|
|
6810
|
-
remainingGenericParams.forEach((parameter) => {
|
|
6811
|
-
parameter.rid = remapGenericParamRid(parameter.rid);
|
|
6812
|
-
});
|
|
6813
|
-
this.tables.rows.set(42, remainingGenericParams);
|
|
6814
|
-
this.tables.counts[42] = remainingGenericParams.length;
|
|
6815
|
-
if (remainingGenericParams.length === 0) this.tables.valid &= ~(1n << 42n);
|
|
6816
|
-
this.genericParams = this.genericParams.filter((parameter) =>
|
|
6817
|
-
!genericParamRids.has(parameter.rid)
|
|
6818
|
-
);
|
|
6819
|
-
for (const parameter of this.genericParams) {
|
|
6820
|
-
parameter.rid = remapGenericParamRid(parameter.rid);
|
|
6821
|
-
}
|
|
6822
|
-
for (const constraint of this.genericParamConstraints) {
|
|
6823
|
-
constraint.ownerRid = remapGenericParamRid(constraint.ownerRid);
|
|
6824
|
-
}
|
|
6825
|
-
}
|
|
6826
|
-
if (genericParamConstraintRids.size > 0) {
|
|
6827
|
-
const remainingConstraints = this.genericParamConstraints.filter((constraint) =>
|
|
6828
|
-
!genericParamConstraintRids.has(constraint.rid)
|
|
6829
|
-
);
|
|
6830
|
-
remainingConstraints.forEach((constraint) => {
|
|
6831
|
-
constraint.rid = remapGenericParamConstraintRid(constraint.rid);
|
|
6832
|
-
});
|
|
6833
|
-
this.genericParamConstraints.splice(
|
|
6834
|
-
0,
|
|
6835
|
-
this.genericParamConstraints.length,
|
|
6836
|
-
...remainingConstraints
|
|
6837
|
-
);
|
|
6838
|
-
const remainingConstraintRows = genericParamConstraintRows.filter((constraint) =>
|
|
6839
|
-
!genericParamConstraintRids.has(constraint.rid)
|
|
6840
|
-
);
|
|
6841
|
-
remainingConstraintRows.forEach((constraint) => {
|
|
6842
|
-
constraint.rid = remapGenericParamConstraintRid(constraint.rid);
|
|
6843
|
-
});
|
|
6844
|
-
this.tables.rows.set(44, remainingConstraintRows);
|
|
6845
|
-
this.tables.counts[44] = remainingConstraintRows.length;
|
|
6846
|
-
if (remainingConstraintRows.length === 0) this.tables.valid &= ~(1n << 44n);
|
|
6847
|
-
}
|
|
6848
|
-
if (parameterRids.size > 0 || genericParamRids.size > 0) {
|
|
6849
|
-
for (const attribute of this.customAttributes) {
|
|
6850
|
-
if (attribute.parent?.table === 8 && !parameterRids.has(attribute.parent.rid)) {
|
|
6851
|
-
attribute.parent = {
|
|
6852
|
-
...attribute.parent,
|
|
6853
|
-
rid: remapParameterRid(attribute.parent.rid)
|
|
6854
|
-
};
|
|
6855
|
-
} else if (attribute.parent?.table === 42 &&
|
|
6856
|
-
!genericParamRids.has(attribute.parent.rid)) {
|
|
6857
|
-
attribute.parent = {
|
|
6858
|
-
...attribute.parent,
|
|
6859
|
-
rid: remapGenericParamRid(attribute.parent.rid)
|
|
6860
|
-
};
|
|
6861
|
-
} else if (attribute.parent?.table === 44 &&
|
|
6862
|
-
!genericParamConstraintRids.has(attribute.parent.rid)) {
|
|
6863
|
-
attribute.parent = {
|
|
6864
|
-
...attribute.parent,
|
|
6865
|
-
rid: remapGenericParamConstraintRid(attribute.parent.rid)
|
|
6866
|
-
};
|
|
6867
|
-
}
|
|
6868
|
-
}
|
|
6869
|
-
}
|
|
6870
|
-
const remainingRows = rows.filter((row) => row.rid !== rid);
|
|
6871
|
-
remainingRows.forEach((row, index) => {
|
|
6872
|
-
row.rid = index + 1;
|
|
6873
|
-
});
|
|
6874
|
-
this.tables.rows.set(6, remainingRows);
|
|
6875
|
-
this.tables.counts[6] = remainingRows.length;
|
|
6876
|
-
if (remainingRows.length === 0) this.tables.valid &= ~(1n << 6n);
|
|
6877
|
-
for (const type of this.types) {
|
|
6878
|
-
type.methodRids = type.methodRids
|
|
6879
|
-
.filter((methodRid) => methodRid !== rid)
|
|
6880
|
-
.map((methodRid) => methodRid > rid ? methodRid - 1 : methodRid);
|
|
6881
|
-
type.methods = type.methods.filter((candidate) => candidate.rid !== rid);
|
|
6882
|
-
for (const candidate of type.methods) {
|
|
6883
|
-
if (candidate.rid > rid) candidate.rid--;
|
|
6884
|
-
}
|
|
6885
|
-
}
|
|
6886
|
-
this.methods.splice(rid - 1, 1);
|
|
6887
|
-
this.methods.forEach((candidate, index) => {
|
|
6888
|
-
candidate.rid = index + 1;
|
|
6889
|
-
});
|
|
6890
|
-
for (const parameter of this.genericParams) {
|
|
6891
|
-
if (parameter.owner.table === 6 && parameter.owner.rid > rid) {
|
|
6892
|
-
parameter.owner = { ...parameter.owner, rid: parameter.owner.rid - 1 };
|
|
6893
|
-
}
|
|
6894
|
-
}
|
|
6895
|
-
for (const memberRef of this.memberRefs) {
|
|
6896
|
-
if (memberRef.parent?.table === 6 && memberRef.parent.rid > rid) {
|
|
6897
|
-
memberRef.parent = { ...memberRef.parent, rid: memberRef.parent.rid - 1 };
|
|
6898
|
-
}
|
|
6899
|
-
}
|
|
6900
|
-
for (const methodSpec of this.methodSpecs) {
|
|
6901
|
-
if (methodSpec.method?.table === 6 && methodSpec.method.rid > rid) {
|
|
6902
|
-
methodSpec.method = { ...methodSpec.method, rid: methodSpec.method.rid - 1 };
|
|
6903
|
-
}
|
|
6904
|
-
}
|
|
6905
|
-
for (const attribute of this.customAttributes) {
|
|
6906
|
-
if (attribute.parent?.table === 6 && attribute.parent.rid > rid) {
|
|
6907
|
-
attribute.parent = { ...attribute.parent, rid: attribute.parent.rid - 1 };
|
|
6908
|
-
}
|
|
6909
|
-
}
|
|
6910
|
-
const remappedBodyCache = new Map();
|
|
6911
|
-
for (const [methodRid, body] of this._bodyCache) {
|
|
6912
|
-
if (methodRid === rid) continue;
|
|
6913
|
-
remappedBodyCache.set(methodRid > rid ? methodRid - 1 : methodRid, body);
|
|
6914
|
-
}
|
|
6915
|
-
this._bodyCache = remappedBodyCache;
|
|
6916
|
-
this._addedMethodBodies.delete(rid);
|
|
6917
|
-
this._bodyCache.delete(rid);
|
|
6918
|
-
this._metadataDirty = true;
|
|
6919
|
-
return tokenMap;
|
|
6920
|
-
}
|
|
6921
|
-
|
|
6922
|
-
addParam({ owner, name = "", sequence, flags = 0 }) {
|
|
6923
|
-
return this.#writeParam({ owner, name, sequence, flags }, false).rid;
|
|
6924
|
-
}
|
|
6925
|
-
|
|
6926
|
-
insertParam({ owner, name = "", sequence, flags = 0 }) {
|
|
6927
|
-
return this.#writeParam({ owner, name, sequence, flags }, true);
|
|
6928
|
-
}
|
|
6929
|
-
|
|
6930
|
-
#writeParam({ owner, name = "", sequence, flags = 0 }, insertIntoOwner) {
|
|
6931
|
-
this.#ensureEditable();
|
|
6932
|
-
const ownerRid = metadataTableId(owner?.table) === 6 ? owner.rid : 0;
|
|
6933
|
-
const method = this.methods[ownerRid - 1];
|
|
6934
|
-
if (!Number.isInteger(ownerRid) || ownerRid < 1 || !method) {
|
|
6935
|
-
throw new RangeError("Param owner must identify an existing MethodDef");
|
|
6936
|
-
}
|
|
6937
|
-
if (typeof name !== "string" || name.includes("\0")) {
|
|
6938
|
-
throw new TypeError("Param name must be a null-free string");
|
|
5838
|
+
if (typeof name !== "string" || name.includes("\0")) {
|
|
5839
|
+
throw new TypeError("Param name must be a null-free string");
|
|
6939
5840
|
}
|
|
6940
5841
|
if (!Number.isInteger(flags) || flags < 0 || flags > 0xffff) {
|
|
6941
5842
|
throw new RangeError("Param flags must be an unsigned 16-bit integer");
|
|
@@ -7256,252 +6157,7 @@ export class Assembly {
|
|
|
7256
6157
|
}
|
|
7257
6158
|
|
|
7258
6159
|
reorderPointerTable(pointerTable, targetRids) {
|
|
7259
|
-
this.#
|
|
7260
|
-
const pointerTableId = metadataTableId(pointerTable);
|
|
7261
|
-
const definitions = new Map([
|
|
7262
|
-
[3, { targetTableId: 4, column: "Field", owners: this.types, list: "fieldRids", records: "fields" }],
|
|
7263
|
-
[5, { targetTableId: 6, column: "Method", owners: this.types, list: "methodRids", records: "methods" }],
|
|
7264
|
-
[7, {
|
|
7265
|
-
targetTableId: 8,
|
|
7266
|
-
column: "Param",
|
|
7267
|
-
owners: this.methods,
|
|
7268
|
-
list: "parameterRids",
|
|
7269
|
-
records: "parameters"
|
|
7270
|
-
}],
|
|
7271
|
-
[19, { targetTableId: 20, column: "Event", owners: this.types, list: "eventRids", records: "events" }],
|
|
7272
|
-
[22, {
|
|
7273
|
-
targetTableId: 23,
|
|
7274
|
-
column: "Property",
|
|
7275
|
-
owners: this.types,
|
|
7276
|
-
list: "propertyRids",
|
|
7277
|
-
records: "properties"
|
|
7278
|
-
}]
|
|
7279
|
-
]);
|
|
7280
|
-
const definition = definitions.get(pointerTableId);
|
|
7281
|
-
if (!definition) {
|
|
7282
|
-
throw new TypeError("Pointer table must be FieldPtr, MethodPtr, ParamPtr, EventPtr, or PropertyPtr");
|
|
7283
|
-
}
|
|
7284
|
-
const allowsCrossOwnerFields = pointerTableId === 3;
|
|
7285
|
-
const allowsCrossOwnerMethods = pointerTableId === 5;
|
|
7286
|
-
const allowsCrossOwnerParameters = pointerTableId === 7;
|
|
7287
|
-
const allowsCrossOwnerEvents = pointerTableId === 19;
|
|
7288
|
-
const allowsCrossOwnerProperties = pointerTableId === 22;
|
|
7289
|
-
if ((this.tables.valid & (1n << BigInt(pointerTableId))) === 0n) {
|
|
7290
|
-
throw new UnsupportedFormatError(`${metadataTableNames[pointerTableId]} is not present`);
|
|
7291
|
-
}
|
|
7292
|
-
const pointerRows = getBijectivePointerRows(
|
|
7293
|
-
this,
|
|
7294
|
-
pointerTableId,
|
|
7295
|
-
definition.targetTableId,
|
|
7296
|
-
definition.column
|
|
7297
|
-
);
|
|
7298
|
-
if (!pointerRows) {
|
|
7299
|
-
throw new FormatError(
|
|
7300
|
-
`${metadataTableNames[pointerTableId]} must be a one-to-one mapping to ${metadataTableNames[definition.targetTableId]}`
|
|
7301
|
-
);
|
|
7302
|
-
}
|
|
7303
|
-
const targetCount = this.tables.counts[definition.targetTableId] ?? 0;
|
|
7304
|
-
if (!Array.isArray(targetRids) || targetRids.length !== targetCount) {
|
|
7305
|
-
throw new RangeError("Pointer table order must contain every target row exactly once");
|
|
7306
|
-
}
|
|
7307
|
-
const newRids = [...targetRids];
|
|
7308
|
-
const uniqueRids = new Set(newRids);
|
|
7309
|
-
if (uniqueRids.size !== targetCount ||
|
|
7310
|
-
newRids.some((rid) => !Number.isInteger(rid) || rid < 1 || rid > targetCount)) {
|
|
7311
|
-
throw new RangeError("Pointer table order must contain every target row exactly once");
|
|
7312
|
-
}
|
|
7313
|
-
|
|
7314
|
-
const ownerGroups = definition.owners.map((owner) => owner[definition.list]);
|
|
7315
|
-
const currentOwnerRids = ownerGroups.flat();
|
|
7316
|
-
if (currentOwnerRids.length !== targetCount ||
|
|
7317
|
-
new Set(currentOwnerRids).size !== targetCount) {
|
|
7318
|
-
throw new FormatError(
|
|
7319
|
-
`${metadataTableNames[definition.targetTableId]} ownership does not cover every row exactly once`
|
|
7320
|
-
);
|
|
7321
|
-
}
|
|
7322
|
-
const currentOwnerByRid = new Map();
|
|
7323
|
-
for (let index = 0; index < ownerGroups.length; index++) {
|
|
7324
|
-
for (const rid of ownerGroups[index]) {
|
|
7325
|
-
currentOwnerByRid.set(rid, definition.owners[index].rid);
|
|
7326
|
-
}
|
|
7327
|
-
}
|
|
7328
|
-
const assignments = [];
|
|
7329
|
-
let offset = 0;
|
|
7330
|
-
const recordsByRid = new Map(
|
|
7331
|
-
definition.owners.flatMap((owner) =>
|
|
7332
|
-
owner[definition.records].map((record) => [record.rid, record])
|
|
7333
|
-
)
|
|
7334
|
-
);
|
|
7335
|
-
for (let index = 0; index < definition.owners.length; index++) {
|
|
7336
|
-
const owner = definition.owners[index];
|
|
7337
|
-
const oldGroup = ownerGroups[index];
|
|
7338
|
-
const nextGroup = newRids.slice(offset, offset + oldGroup.length);
|
|
7339
|
-
offset += oldGroup.length;
|
|
7340
|
-
const oldSet = new Set(oldGroup);
|
|
7341
|
-
const movesRowsAcrossOwners = nextGroup.some((rid) => !oldSet.has(rid));
|
|
7342
|
-
const allowsCrossOwnerRows = allowsCrossOwnerFields || allowsCrossOwnerMethods ||
|
|
7343
|
-
allowsCrossOwnerParameters || allowsCrossOwnerEvents || allowsCrossOwnerProperties;
|
|
7344
|
-
if (!allowsCrossOwnerRows && movesRowsAcrossOwners) {
|
|
7345
|
-
throw new UnsupportedFormatError("Pointer reordering cannot change row ownership");
|
|
7346
|
-
}
|
|
7347
|
-
const nextRecords = nextGroup.map((rid) => recordsByRid.get(rid));
|
|
7348
|
-
if (nextRecords.some((record) => !record)) {
|
|
7349
|
-
throw new FormatError(`${metadataTableNames[definition.targetTableId]} ownership has no semantic record`);
|
|
7350
|
-
}
|
|
7351
|
-
const movedRecords = nextRecords.filter((record) =>
|
|
7352
|
-
currentOwnerByRid.get(record.rid) !== owner.rid
|
|
7353
|
-
);
|
|
7354
|
-
if (allowsCrossOwnerFields) {
|
|
7355
|
-
for (const record of movedRecords) {
|
|
7356
|
-
const parsed = parseSignature(record.signature, { counts: this.tables.counts });
|
|
7357
|
-
if (parsed.kind !== "field") {
|
|
7358
|
-
throw new FormatError(`Field row ${record.rid} has a non-field signature`);
|
|
7359
|
-
}
|
|
7360
|
-
validateGenericVariableReferences(
|
|
7361
|
-
parsed,
|
|
7362
|
-
getGenericParameterArity(this.genericParams, 2, owner.rid),
|
|
7363
|
-
this
|
|
7364
|
-
);
|
|
7365
|
-
if ((this.tables.rows.get(16) ?? []).some((layout) =>
|
|
7366
|
-
layout.Field.rid === record.rid
|
|
7367
|
-
) && (owner.flags & 0x0018) !== 0x0010) {
|
|
7368
|
-
throw new UnsupportedFormatError(
|
|
7369
|
-
`Field row ${record.rid} has an explicit offset and requires an explicit-layout owner`
|
|
7370
|
-
);
|
|
7371
|
-
}
|
|
7372
|
-
}
|
|
7373
|
-
}
|
|
7374
|
-
if (allowsCrossOwnerParameters && movesRowsAcrossOwners) {
|
|
7375
|
-
const signature = parseSignature(owner.signature, { counts: this.tables.counts });
|
|
7376
|
-
if (signature.kind !== "method") {
|
|
7377
|
-
throw new FormatError(`MethodDef row ${owner.rid} has a non-method signature`);
|
|
7378
|
-
}
|
|
7379
|
-
const sequences = new Set();
|
|
7380
|
-
for (const record of nextRecords) {
|
|
7381
|
-
if (!Number.isInteger(record.sequence) || record.sequence < 0 ||
|
|
7382
|
-
record.sequence > signature.parameters.length) {
|
|
7383
|
-
throw new FormatError(
|
|
7384
|
-
`Param row ${record.rid} sequence exceeds MethodDef row ${owner.rid}'s signature`
|
|
7385
|
-
);
|
|
7386
|
-
}
|
|
7387
|
-
if (sequences.has(record.sequence)) {
|
|
7388
|
-
throw new FormatError(
|
|
7389
|
-
`MethodDef row ${owner.rid} would have duplicate Param sequence ${record.sequence}`
|
|
7390
|
-
);
|
|
7391
|
-
}
|
|
7392
|
-
sequences.add(record.sequence);
|
|
7393
|
-
}
|
|
7394
|
-
}
|
|
7395
|
-
if (allowsCrossOwnerMethods && movesRowsAcrossOwners) {
|
|
7396
|
-
if ((owner.flags & (0x0080 | 0x0020)) === 0) {
|
|
7397
|
-
throw new UnsupportedFormatError(
|
|
7398
|
-
"Pointer reordering cannot move abstract methods to a non-abstract TypeDef"
|
|
7399
|
-
);
|
|
7400
|
-
}
|
|
7401
|
-
for (const record of movedRecords) {
|
|
7402
|
-
if (record.rva !== 0 || (record.flags & 0x0440) !== 0x0440 ||
|
|
7403
|
-
record.genericParams.length > 0) {
|
|
7404
|
-
throw new UnsupportedFormatError(
|
|
7405
|
-
"Cross-owner MethodPtr reordering supports only bodyless, non-generic abstract virtual methods"
|
|
7406
|
-
);
|
|
7407
|
-
}
|
|
7408
|
-
const signature = parseSignature(record.signature, { counts: this.tables.counts });
|
|
7409
|
-
if (signature.kind !== "method") {
|
|
7410
|
-
throw new FormatError(`MethodDef row ${record.rid} has a non-method signature`);
|
|
7411
|
-
}
|
|
7412
|
-
if ((signature.genericParameterCount ?? 0) > 0) {
|
|
7413
|
-
throw new UnsupportedFormatError(
|
|
7414
|
-
"Cross-owner MethodPtr reordering does not support generic methods"
|
|
7415
|
-
);
|
|
7416
|
-
}
|
|
7417
|
-
validateGenericVariableReferences(
|
|
7418
|
-
signature,
|
|
7419
|
-
getGenericParameterArity(this.genericParams, 2, owner.rid),
|
|
7420
|
-
this,
|
|
7421
|
-
null,
|
|
7422
|
-
signature.genericParameterCount ?? 0
|
|
7423
|
-
);
|
|
7424
|
-
const hasMethodSemantics = (this.tables.rows.get(24) ?? []).some((row) =>
|
|
7425
|
-
row.Method.rid === record.rid
|
|
7426
|
-
);
|
|
7427
|
-
const hasMethodImpl = (this.tables.rows.get(25) ?? []).some((row) =>
|
|
7428
|
-
row.MethodBody.target?.table === 6 && row.MethodBody.target.rid === record.rid ||
|
|
7429
|
-
row.MethodDeclaration.target?.table === 6 && row.MethodDeclaration.target.rid === record.rid
|
|
7430
|
-
);
|
|
7431
|
-
if (hasMethodSemantics || hasMethodImpl) {
|
|
7432
|
-
throw new UnsupportedFormatError(
|
|
7433
|
-
"Pointer reordering cannot change row ownership for methods with semantics or MethodImpl rows"
|
|
7434
|
-
);
|
|
7435
|
-
}
|
|
7436
|
-
}
|
|
7437
|
-
}
|
|
7438
|
-
if (allowsCrossOwnerEvents && movesRowsAcrossOwners) {
|
|
7439
|
-
for (const record of movedRecords) {
|
|
7440
|
-
const hasSemantics = (this.tables.rows.get(24) ?? []).some((row) =>
|
|
7441
|
-
row.Association.target?.table === 20 && row.Association.target.rid === record.rid
|
|
7442
|
-
);
|
|
7443
|
-
if (hasSemantics) {
|
|
7444
|
-
throw new UnsupportedFormatError(
|
|
7445
|
-
"Pointer reordering cannot change row ownership for events with MethodSemantics rows"
|
|
7446
|
-
);
|
|
7447
|
-
}
|
|
7448
|
-
if (record.eventType.table === 27) {
|
|
7449
|
-
const typeArity = getGenericParameterArity(this.genericParams, 2, owner.rid);
|
|
7450
|
-
const typeSpec = this.typeSpecs[record.eventType.rid - 1];
|
|
7451
|
-
if (!typeSpec) {
|
|
7452
|
-
throw new FormatError(`Event row ${record.rid} references missing TypeSpec row ${record.eventType.rid}`);
|
|
7453
|
-
}
|
|
7454
|
-
validateTypeSpecDefinitions(this, typeSpec.parsedSignature);
|
|
7455
|
-
validateTypeSpecGenericContext(this, record.eventType.rid, typeArity);
|
|
7456
|
-
}
|
|
7457
|
-
}
|
|
7458
|
-
}
|
|
7459
|
-
if (allowsCrossOwnerProperties && movesRowsAcrossOwners) {
|
|
7460
|
-
for (const record of movedRecords) {
|
|
7461
|
-
const hasSemantics = (this.tables.rows.get(24) ?? []).some((row) =>
|
|
7462
|
-
row.Association.target?.table === 23 && row.Association.target.rid === record.rid
|
|
7463
|
-
);
|
|
7464
|
-
if (hasSemantics) {
|
|
7465
|
-
throw new UnsupportedFormatError(
|
|
7466
|
-
"Pointer reordering cannot change row ownership for properties with MethodSemantics rows"
|
|
7467
|
-
);
|
|
7468
|
-
}
|
|
7469
|
-
const signature = parseSignature(record.signature, { counts: this.tables.counts });
|
|
7470
|
-
if (signature.kind !== "property") {
|
|
7471
|
-
throw new FormatError(`Property row ${record.rid} has a non-property signature`);
|
|
7472
|
-
}
|
|
7473
|
-
validateGenericVariableReferences(
|
|
7474
|
-
signature,
|
|
7475
|
-
getGenericParameterArity(this.genericParams, 2, owner.rid),
|
|
7476
|
-
this
|
|
7477
|
-
);
|
|
7478
|
-
}
|
|
7479
|
-
}
|
|
7480
|
-
assignments.push({ owner, nextGroup, nextRecords });
|
|
7481
|
-
}
|
|
7482
|
-
if (offset !== targetCount) {
|
|
7483
|
-
throw new FormatError(
|
|
7484
|
-
`${metadataTableNames[definition.targetTableId]} ownership does not cover every row exactly once`
|
|
7485
|
-
);
|
|
7486
|
-
}
|
|
7487
|
-
|
|
7488
|
-
const nextPointerRows = newRids.map((rid, index) => ({
|
|
7489
|
-
...pointerRows[index],
|
|
7490
|
-
rid: index + 1,
|
|
7491
|
-
[definition.column]: {
|
|
7492
|
-
raw: rid,
|
|
7493
|
-
table: definition.targetTableId,
|
|
7494
|
-
tableName: metadataTableNames[definition.targetTableId],
|
|
7495
|
-
rid
|
|
7496
|
-
}
|
|
7497
|
-
}));
|
|
7498
|
-
this.tables.rows.set(pointerTableId, nextPointerRows);
|
|
7499
|
-
for (const assignment of assignments) {
|
|
7500
|
-
assignment.owner[definition.list] = assignment.nextGroup;
|
|
7501
|
-
assignment.owner[definition.records] = assignment.nextRecords;
|
|
7502
|
-
}
|
|
7503
|
-
this._metadataDirty = true;
|
|
7504
|
-
return this;
|
|
6160
|
+
return this.#pointerTableEditor.reorderPointerTable.call(this, pointerTable, targetRids);
|
|
7505
6161
|
}
|
|
7506
6162
|
|
|
7507
6163
|
addField({ owner, name, flags = 0, signature }) {
|
|
@@ -8562,147 +7218,23 @@ export class Assembly {
|
|
|
8562
7218
|
}
|
|
8563
7219
|
|
|
8564
7220
|
setInstructionOperand(methodRid, instructionOffset, value) {
|
|
8565
|
-
this.#
|
|
8566
|
-
const body = this.getMethodBody(methodRid);
|
|
8567
|
-
if (!body) throw new FormatError("Method has no CIL body");
|
|
8568
|
-
const instruction = body.instructions.find((candidate) => candidate.offset === instructionOffset);
|
|
8569
|
-
if (!instruction) throw new RangeError(`No instruction begins at IL_${instructionOffset.toString(16)}`);
|
|
8570
|
-
if (!instruction.operand) throw new TypeError("Instruction has no operand");
|
|
8571
|
-
|
|
8572
|
-
if (instruction.operand.kind === "branch") {
|
|
8573
|
-
this.#validateBranchTarget(body, value);
|
|
8574
|
-
} else if (instruction.operand.kind === "switch") {
|
|
8575
|
-
if (!Array.isArray(value)) throw new TypeError("Switch operand must be an array of IL target offsets");
|
|
8576
|
-
for (const target of value) this.#validateBranchTarget(body, target);
|
|
8577
|
-
} else if (instruction.opcode.name === "ldstr") {
|
|
8578
|
-
if (!Number.isInteger(value) || (value >>> 24) !== 0x70) {
|
|
8579
|
-
throw new TypeError("ldstr operand must be a 0x70-prefixed user-string token");
|
|
8580
|
-
}
|
|
8581
|
-
this.heaps.getUserString(value);
|
|
8582
|
-
} else if (instruction.operand.kind === "token") {
|
|
8583
|
-
if (!Number.isInteger(value) || value < 0 || value > 0xffffffff) {
|
|
8584
|
-
throw new RangeError("Metadata token must be an unsigned 32-bit integer");
|
|
8585
|
-
}
|
|
8586
|
-
const table = value >>> 24;
|
|
8587
|
-
const rid = value & 0x00ffffff;
|
|
8588
|
-
if (!allowedTokenTables(instruction.opcode.name).includes(table)) {
|
|
8589
|
-
throw new FormatError(`Metadata table ${table} is not valid for ${instruction.opcode.name}`);
|
|
8590
|
-
}
|
|
8591
|
-
if (rid === 0 || rid > (this.tables.counts[table] ?? 0)) {
|
|
8592
|
-
throw new RangeError(`${instruction.opcode.name} references missing ${metadataTableNames[table]} row ${rid}`);
|
|
8593
|
-
}
|
|
8594
|
-
validateInstructionGenericContext(this, methodRid, instruction, value);
|
|
8595
|
-
}
|
|
8596
|
-
|
|
8597
|
-
if (instruction.operand.kind === "branch" && instruction.operand.targetOffset === value) return this;
|
|
8598
|
-
if (instruction.operand.kind === "switch" &&
|
|
8599
|
-
instruction.operand.targetOffsets.length === value.length &&
|
|
8600
|
-
instruction.operand.targetOffsets.every((target, index) => target === value[index])) return this;
|
|
8601
|
-
if (instruction.operand.kind !== "branch" && instruction.operand.kind !== "switch" &&
|
|
8602
|
-
instruction.operand.value === value) return this;
|
|
8603
|
-
|
|
8604
|
-
if (this._structuralBodies.has(methodRid) || this._addedMethodBodies.has(methodRid)) {
|
|
8605
|
-
const state = this.#createStructuralState(methodRid);
|
|
8606
|
-
const editableInstruction = state.instructions.find((candidate) => candidate.offset === instructionOffset);
|
|
8607
|
-
updateStructuralOperand(state, editableInstruction, value);
|
|
8608
|
-
this.#commitStructuralState(methodRid, state);
|
|
8609
|
-
} else {
|
|
8610
|
-
const patches = createOperandPatches(instruction, value);
|
|
8611
|
-
for (const patch of patches) this._patches.push(patch);
|
|
8612
|
-
instruction.operand = instruction.operand.kind === "branch"
|
|
8613
|
-
? { kind: "branch", targetOffset: value }
|
|
8614
|
-
: instruction.operand.kind === "switch"
|
|
8615
|
-
? { kind: "switch", targetOffsets: [...value] }
|
|
8616
|
-
: { ...instruction.operand, value };
|
|
8617
|
-
}
|
|
8618
|
-
return this;
|
|
7221
|
+
return this.#instructionEditor.setInstructionOperand(methodRid, instructionOffset, value);
|
|
8619
7222
|
}
|
|
8620
7223
|
|
|
8621
7224
|
setInstructionOpcode(methodRid, instructionOffset, opcodeNameOrCode) {
|
|
8622
|
-
this.#
|
|
8623
|
-
const body = this.getMethodBody(methodRid);
|
|
8624
|
-
if (!body) throw new FormatError("Method has no CIL body");
|
|
8625
|
-
const instruction = body.instructions.find((candidate) => candidate.offset === instructionOffset);
|
|
8626
|
-
if (!instruction) throw new RangeError(`No instruction begins at IL_${instructionOffset.toString(16)}`);
|
|
8627
|
-
const opcode = listOpcodes().find((candidate) =>
|
|
8628
|
-
candidate.name === opcodeNameOrCode || candidate.code === opcodeNameOrCode
|
|
8629
|
-
);
|
|
8630
|
-
if (!opcode) throw new RangeError(`Unknown CIL opcode ${opcodeNameOrCode}`);
|
|
8631
|
-
const encoded = encodeOpcode(opcode);
|
|
8632
|
-
if (encoded.length !== instruction.opcodeSize || opcode.operand !== instruction.opcode.operand) {
|
|
8633
|
-
throw new FormatError("Opcode edit must preserve the opcode and operand widths");
|
|
8634
|
-
}
|
|
8635
|
-
if (opcode.code === instruction.opcode.code) return this;
|
|
8636
|
-
if (instruction.operand?.kind === "token") {
|
|
8637
|
-
if (opcode.name !== "ldstr") {
|
|
8638
|
-
const table = instruction.operand.value >>> 24;
|
|
8639
|
-
const rid = instruction.operand.value & 0x00ffffff;
|
|
8640
|
-
if (!allowedTokenTables(opcode.name).includes(table)) {
|
|
8641
|
-
throw new FormatError(`Metadata table ${table} is not valid for ${opcode.name}`);
|
|
8642
|
-
}
|
|
8643
|
-
if (rid === 0 || rid > (this.tables.counts[table] ?? 0)) {
|
|
8644
|
-
throw new RangeError(`${opcode.name} references missing ${metadataTableNames[table]} row ${rid}`);
|
|
8645
|
-
}
|
|
8646
|
-
validateInstructionGenericContext(
|
|
8647
|
-
this, methodRid, { ...instruction, opcode }, instruction.operand.value
|
|
8648
|
-
);
|
|
8649
|
-
}
|
|
8650
|
-
}
|
|
8651
|
-
if (this._structuralBodies.has(methodRid) || this._addedMethodBodies.has(methodRid)) {
|
|
8652
|
-
const state = this.#createStructuralState(methodRid);
|
|
8653
|
-
const editableInstruction = state.instructions.find((candidate) => candidate.offset === instructionOffset);
|
|
8654
|
-
editableInstruction.opcode = opcode;
|
|
8655
|
-
layoutStructuralState(state);
|
|
8656
|
-
this.#commitStructuralState(methodRid, state);
|
|
8657
|
-
} else {
|
|
8658
|
-
this._patches.push({ offset: instruction.opcodeOffset, bytes: encoded });
|
|
8659
|
-
instruction.opcode = opcode;
|
|
8660
|
-
}
|
|
8661
|
-
return this;
|
|
7225
|
+
return this.#instructionEditor.setInstructionOpcode(methodRid, instructionOffset, opcodeNameOrCode);
|
|
8662
7226
|
}
|
|
8663
7227
|
|
|
8664
7228
|
insertInstruction(methodRid, beforeOffset, opcodeNameOrCode, operand) {
|
|
8665
|
-
this.#
|
|
8666
|
-
const opcode = listOpcodes().find((candidate) =>
|
|
8667
|
-
candidate.name === opcodeNameOrCode || candidate.code === opcodeNameOrCode
|
|
8668
|
-
);
|
|
8669
|
-
if (!opcode) throw new RangeError(`Unknown CIL opcode ${opcodeNameOrCode}`);
|
|
8670
|
-
const state = this.#createStructuralState(methodRid);
|
|
8671
|
-
const instruction = insertStructuralInstruction(state, beforeOffset, opcode, operand);
|
|
8672
|
-
if (instruction.operand?.kind === "token" && opcode.name !== "ldstr") {
|
|
8673
|
-
const token = instruction.operand.value;
|
|
8674
|
-
const table = token >>> 24;
|
|
8675
|
-
const rid = token & 0x00ffffff;
|
|
8676
|
-
if (!allowedTokenTables(opcode.name).includes(table)) {
|
|
8677
|
-
throw new FormatError(`Metadata table ${table} is not valid for ${opcode.name}`);
|
|
8678
|
-
}
|
|
8679
|
-
if (rid === 0 || rid > (this.tables.counts[table] ?? 0)) {
|
|
8680
|
-
throw new RangeError(`${opcode.name} references missing ${metadataTableNames[table]} row ${rid}`);
|
|
8681
|
-
}
|
|
8682
|
-
validateInstructionGenericContext(this, methodRid, instruction, token);
|
|
8683
|
-
}
|
|
8684
|
-
this.#commitStructuralState(methodRid, state);
|
|
8685
|
-
return instruction;
|
|
7229
|
+
return this.#instructionEditor.insertInstruction(methodRid, beforeOffset, opcodeNameOrCode, operand);
|
|
8686
7230
|
}
|
|
8687
7231
|
|
|
8688
7232
|
removeInstruction(methodRid, instructionOffset) {
|
|
8689
|
-
this.#
|
|
8690
|
-
const state = this.#createStructuralState(methodRid);
|
|
8691
|
-
const instruction = removeStructuralInstruction(state, instructionOffset);
|
|
8692
|
-
this.#commitStructuralState(methodRid, state);
|
|
8693
|
-
return instruction;
|
|
7233
|
+
return this.#instructionEditor.removeInstruction(methodRid, instructionOffset);
|
|
8694
7234
|
}
|
|
8695
7235
|
|
|
8696
7236
|
setMethodMaxStack(methodRid, maxStack) {
|
|
8697
|
-
this.#
|
|
8698
|
-
if (!Number.isInteger(maxStack) || maxStack < 0 || maxStack > 0xffff) {
|
|
8699
|
-
throw new RangeError("maxStack must be an unsigned 16-bit integer");
|
|
8700
|
-
}
|
|
8701
|
-
const state = this.#createStructuralState(methodRid);
|
|
8702
|
-
state.maxStack = maxStack;
|
|
8703
|
-
layoutStructuralState(state);
|
|
8704
|
-
this.#commitStructuralState(methodRid, state);
|
|
8705
|
-
return this;
|
|
7237
|
+
return this.#instructionEditor.setMethodMaxStack(methodRid, maxStack);
|
|
8706
7238
|
}
|
|
8707
7239
|
|
|
8708
7240
|
addMemberRef({ parent, name, signature }) {
|
|
@@ -14649,9 +13181,9 @@ export class Assembly {
|
|
|
14649
13181
|
if (signature.rva === 0 && (this.cli.flags & 0x08) !== 0) {
|
|
14650
13182
|
throw new FormatError("Strong-name-signed CLI header has no signature directory");
|
|
14651
13183
|
}
|
|
14652
|
-
const expectedSize = Math.ceil(privateKey.
|
|
13184
|
+
const expectedSize = Math.ceil(privateKey.n.bitLength() / 8);
|
|
14653
13185
|
const currentPublicKey = this.heaps.getBlob(assemblyRow.PublicKey);
|
|
14654
|
-
const keyChanged = !
|
|
13186
|
+
const keyChanged = !equalBytes(currentPublicKey, publicKey);
|
|
14655
13187
|
const identityChanged = keyChanged ||
|
|
14656
13188
|
assemblyRow.HashAlgId !== selectedHashAlgorithm ||
|
|
14657
13189
|
(assemblyRow.Flags & 0x01) === 0;
|
|
@@ -14694,11 +13226,11 @@ export class Assembly {
|
|
|
14694
13226
|
getStrongNameHashName(hashAlgorithm);
|
|
14695
13227
|
const expectedPublicKey = encodeStrongNamePublicKey(privateKey, hashAlgorithm);
|
|
14696
13228
|
const currentPublicKey = this.heaps.getBlob(assemblyRow.PublicKey);
|
|
14697
|
-
if (!
|
|
13229
|
+
if (!equalBytes(currentPublicKey, expectedPublicKey)) {
|
|
14698
13230
|
throw new FormatError("Strong-name private key does not match the Assembly public key");
|
|
14699
13231
|
}
|
|
14700
13232
|
const signature = this.cli.strongNameSignature;
|
|
14701
|
-
const expectedSize = Math.ceil(privateKey.
|
|
13233
|
+
const expectedSize = Math.ceil(privateKey.n.bitLength() / 8);
|
|
14702
13234
|
if ((signature.rva === 0) !== (signature.size === 0)) {
|
|
14703
13235
|
throw new FormatError("Strong-name signature directory has only one of RVA and size set");
|
|
14704
13236
|
}
|
|
@@ -14765,7 +13297,8 @@ export class Assembly {
|
|
|
14765
13297
|
}
|
|
14766
13298
|
|
|
14767
13299
|
toBuffer() {
|
|
14768
|
-
|
|
13300
|
+
const bytes = this.serialize();
|
|
13301
|
+
return typeof Buffer === "undefined" ? bytes : Buffer.from(bytes);
|
|
14769
13302
|
}
|
|
14770
13303
|
}
|
|
14771
13304
|
|