diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index b638e2c575..c57d36105c 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -7,3 +7,5 @@
# have proper ownership.
/src/ @dotnet/dotnet-diag
/documentation/ @dotnet/dotnet-diag
+/eng/SourceBuild.props @dotnet/source-build-internal
+/eng/SourceBuildPrebuiltBaseline.xml @dotnet/source-build-internal
diff --git a/.github/fabricbot.json b/.github/fabricbot.json
index 55572d732a..2e190edba0 100644
--- a/.github/fabricbot.json
+++ b/.github/fabricbot.json
@@ -17,7 +17,16 @@
"enforceDMPAsStatus": true,
"removeLabelOnPush": true,
"usePrDescriptionAsCommitMessage": false,
- "conditionalMergeTypes": [],
+ "conditionalMergeTypes": [
+ {
+ "mergeType": "merge",
+ "condition": {
+ "placeholder": "branch",
+ "operator": "equals",
+ "value": "release/stable"
+ }
+ }
+ ],
"requireAllStatuses": true,
"requireSpecificCheckRuns": true,
"requireSpecificCheckRunsList": [
@@ -31,15 +40,13 @@
"DotNet Maestro",
"DotNet Maestro - Int"
]
- },
- "id": "9xknvk-BFN"
+ }
},
{
"taskType": "trigger",
"capabilityId": "IssueResponder",
"subCapability": "PullRequestResponder",
"version": "1.0",
- "id": "DGPtO9UQd",
"config": {
"conditions": {
"operator": "and",
@@ -80,6 +87,948 @@
}
]
}
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssueCommentResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isOpen",
+ "parameters": {}
+ }
+ ]
+ },
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "created"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "Needs: Author Feedback"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "noActivitySince",
+ "parameters": {
+ "days": 30
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isCloseAndComment",
+ "parameters": {}
+ }
+ ]
+ },
+ {
+ "name": "isActivitySender",
+ "parameters": {
+ "user": {
+ "type": "author"
+ }
+ }
+ },
+ {
+ "name": "activitySenderHasPermissions",
+ "parameters": {
+ "permissions": "none"
+ }
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issue_comment"
+ ],
+ "taskName": "[Idle Issue Management] For issues closed due to inactivity, re-open an issue if issue author posts a reply within 30 days.",
+ "actions": [
+ {
+ "name": "reopenIssue",
+ "parameters": {}
+ },
+ {
+ "name": "removeLabel",
+ "parameters": {
+ "label": "Status: No Recent Activity"
+ }
+ },
+ {
+ "name": "removeLabel",
+ "parameters": {
+ "label": "Needs: Author Feedback"
+ }
+ },
+ {
+ "name": "addLabel",
+ "parameters": {
+ "label": "Needs: Attention :wave:"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssueCommentResponder",
+ "version": "1.0",
+ "config": {
+ "taskName": "[Idle Issue Management] Replace needs author feedback label with needs attention label when the author comments on an issue",
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "created"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "Needs: Author Feedback"
+ }
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ },
+ {
+ "name": "isActivitySender",
+ "parameters": {
+ "user": {
+ "type": "author"
+ }
+ }
+ }
+ ]
+ },
+ "actions": [
+ {
+ "name": "addLabel",
+ "parameters": {
+ "label": "Needs: Attention :wave:"
+ }
+ },
+ {
+ "name": "removeLabel",
+ "parameters": {
+ "label": "Needs: Author Feedback"
+ }
+ }
+ ],
+ "eventType": "issue",
+ "eventNames": [
+ "issue_comment"
+ ]
+ }
+ },
+ {
+ "taskType": "scheduled",
+ "capabilityId": "ScheduledSearch",
+ "subCapability": "ScheduledSearch",
+ "version": "1.1",
+ "config": {
+ "taskName": "[Idle Issue Management] Close stale issues",
+ "frequency": [
+ {
+ "weekDay": 1,
+ "hours": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23
+ ]
+ },
+ {
+ "weekDay": 2,
+ "hours": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23
+ ]
+ },
+ {
+ "weekDay": 3,
+ "hours": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23
+ ]
+ },
+ {
+ "weekDay": 4,
+ "hours": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23
+ ]
+ },
+ {
+ "weekDay": 5,
+ "hours": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23
+ ]
+ }
+ ],
+ "searchTerms": [
+ {
+ "name": "isIssue",
+ "parameters": {}
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "Needs: Author Feedback"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "Status: No Recent Activity"
+ }
+ },
+ {
+ "name": "noActivitySince",
+ "parameters": {
+ "days": 3
+ }
+ }
+ ],
+ "actions": [
+ {
+ "name": "addReply",
+ "parameters": {
+ "comment": "Hi @${issueAuthor}. We are closing this issue due to inactivity. If you comment within 30 days it will automatically reopen. If you are not the author of this issue and you're facing the same problem, feel free to open a new issue referencing this one."
+ }
+ },
+ {
+ "name": "closeIssue",
+ "parameters": {}
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "scheduled",
+ "capabilityId": "ScheduledSearch",
+ "subCapability": "ScheduledSearch",
+ "version": "1.1",
+ "config": {
+ "taskName": "[Idle Issue Management] Add no recent activity label to issues",
+ "frequency": [
+ {
+ "weekDay": 1,
+ "hours": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23
+ ]
+ },
+ {
+ "weekDay": 2,
+ "hours": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23
+ ]
+ },
+ {
+ "weekDay": 3,
+ "hours": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23
+ ]
+ },
+ {
+ "weekDay": 4,
+ "hours": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23
+ ]
+ },
+ {
+ "weekDay": 5,
+ "hours": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23
+ ]
+ }
+ ],
+ "searchTerms": [
+ {
+ "name": "isIssue",
+ "parameters": {}
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "Needs: Author Feedback"
+ }
+ },
+ {
+ "name": "noActivitySince",
+ "parameters": {
+ "days": 4
+ }
+ },
+ {
+ "name": "noLabel",
+ "parameters": {
+ "label": "Status: No Recent Activity"
+ }
+ }
+ ],
+ "actions": [
+ {
+ "name": "addLabel",
+ "parameters": {
+ "label": "Status: No Recent Activity"
+ }
+ },
+ {
+ "name": "addReply",
+ "parameters": {
+ "comment": "This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **4 days**. It will be closed if no further activity occurs **within 3 days of this comment**. If it *is* closed, feel free to comment when you are able to provide the additional information and we will re-investigate."
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "scheduled",
+ "capabilityId": "ScheduledSearch",
+ "subCapability": "ScheduledSearch",
+ "version": "1.1",
+ "config": {
+ "taskName": "[Resolved Issue Management] Close resolved issues",
+ "frequency": [
+ {
+ "weekDay": 0,
+ "hours": [
+ 2,
+ 5,
+ 8,
+ 11,
+ 14,
+ 17,
+ 20,
+ 23
+ ],
+ "timezoneOffset": -8
+ },
+ {
+ "weekDay": 1,
+ "hours": [
+ 2,
+ 5,
+ 8,
+ 11,
+ 14,
+ 17,
+ 20,
+ 23
+ ],
+ "timezoneOffset": -8
+ },
+ {
+ "weekDay": 2,
+ "hours": [
+ 2,
+ 5,
+ 8,
+ 11,
+ 14,
+ 17,
+ 20,
+ 23
+ ],
+ "timezoneOffset": -8
+ },
+ {
+ "weekDay": 3,
+ "hours": [
+ 2,
+ 5,
+ 8,
+ 11,
+ 14,
+ 17,
+ 20,
+ 23
+ ],
+ "timezoneOffset": -8
+ },
+ {
+ "weekDay": 4,
+ "hours": [
+ 2,
+ 5,
+ 8,
+ 11,
+ 14,
+ 17,
+ 20,
+ 23
+ ],
+ "timezoneOffset": -8
+ },
+ {
+ "weekDay": 5,
+ "hours": [
+ 2,
+ 5,
+ 8,
+ 11,
+ 14,
+ 17,
+ 20,
+ 23
+ ],
+ "timezoneOffset": -8
+ },
+ {
+ "weekDay": 6,
+ "hours": [
+ 2,
+ 5,
+ 8,
+ 11,
+ 14,
+ 17,
+ 20,
+ 23
+ ],
+ "timezoneOffset": -8
+ }
+ ],
+ "searchTerms": [
+ {
+ "name": "isIssue",
+ "parameters": {}
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "Status: Resolved"
+ }
+ },
+ {
+ "name": "noActivitySince",
+ "parameters": {
+ "days": 1
+ }
+ }
+ ],
+ "actions": [
+ {
+ "name": "addReply",
+ "parameters": {
+ "comment": "This issue has been resolved and has not had any activity for **1 day**. It will be closed for housekeeping purposes."
+ }
+ },
+ {
+ "name": "closeIssue",
+ "parameters": {}
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "taskName": "[Closed Issue Management] Remove no recent activity label from issues",
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "closed"
+ }
+ }
+ ]
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "Status: No Recent Activity"
+ }
+ }
+ ]
+ },
+ "actions": [
+ {
+ "name": "removeLabel",
+ "parameters": {
+ "label": "Status: No Recent Activity"
+ }
+ }
+ ],
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssueCommentResponder",
+ "version": "1.0",
+ "config": {
+ "taskName": "[Idle Issue Management] Remove no recent activity label when an issue is commented on",
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "Status: No Recent Activity"
+ }
+ }
+ ]
+ },
+ "actions": [
+ {
+ "name": "removeLabel",
+ "parameters": {
+ "label": "Status: No Recent Activity"
+ }
+ }
+ ],
+ "eventType": "issue",
+ "eventNames": [
+ "issue_comment"
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "Needs: Author Feedback"
+ }
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "Add comment when 'Needs Author Feedback' is applied to issue",
+ "actions": [
+ {
+ "name": "addReply",
+ "parameters": {
+ "comment": "Hi @${issueAuthor}. We have added the \"Needs: Author Feedback\" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time."
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "scheduled",
+ "capabilityId": "ScheduledSearch",
+ "subCapability": "ScheduledSearch",
+ "version": "1.1",
+ "config": {
+ "frequency": [
+ {
+ "weekDay": 0,
+ "hours": [
+ 1,
+ 4,
+ 7,
+ 10,
+ 13,
+ 16,
+ 19,
+ 22
+ ],
+ "timezoneOffset": -8
+ },
+ {
+ "weekDay": 1,
+ "hours": [
+ 1,
+ 4,
+ 7,
+ 10,
+ 13,
+ 16,
+ 19,
+ 22
+ ],
+ "timezoneOffset": -8
+ },
+ {
+ "weekDay": 2,
+ "hours": [
+ 1,
+ 4,
+ 7,
+ 10,
+ 13,
+ 16,
+ 19,
+ 22
+ ],
+ "timezoneOffset": -8
+ },
+ {
+ "weekDay": 3,
+ "hours": [
+ 1,
+ 4,
+ 7,
+ 10,
+ 13,
+ 16,
+ 19,
+ 22
+ ],
+ "timezoneOffset": -8
+ },
+ {
+ "weekDay": 4,
+ "hours": [
+ 1,
+ 4,
+ 7,
+ 10,
+ 13,
+ 16,
+ 19,
+ 22
+ ],
+ "timezoneOffset": -8
+ },
+ {
+ "weekDay": 5,
+ "hours": [
+ 1,
+ 4,
+ 7,
+ 10,
+ 13,
+ 16,
+ 19,
+ 22
+ ],
+ "timezoneOffset": -8
+ },
+ {
+ "weekDay": 6,
+ "hours": [
+ 1,
+ 4,
+ 7,
+ 10,
+ 13,
+ 16,
+ 19,
+ 22
+ ],
+ "timezoneOffset": -8
+ }
+ ],
+ "searchTerms": [
+ {
+ "name": "isClosed",
+ "parameters": {}
+ },
+ {
+ "name": "noActivitySince",
+ "parameters": {
+ "days": 30
+ }
+ },
+ {
+ "name": "isUnlocked",
+ "parameters": {}
+ },
+ {
+ "name": "isIssue",
+ "parameters": {}
+ },
+ {
+ "name": "noLabel",
+ "parameters": {
+ "label": "Bot: Do Not Lock"
+ }
+ }
+ ],
+ "taskName": "[Closed Issue Management] Lock issues closed without activity for over 30 days",
+ "actions": [
+ {
+ "name": "lockIssue",
+ "parameters": {
+ "reason": "resolved"
+ }
+ }
+ ]
+ }
}
],
"userGroups": []
diff --git a/diagnostics.yml b/diagnostics.yml
index 599fce356f..bd0e5e5a6d 100644
--- a/diagnostics.yml
+++ b/diagnostics.yml
@@ -473,6 +473,8 @@ extends:
enable: true
continueOnError: true
params: ' -SourceToolsList @("policheck","credscan")
+ -ArtifactToolsList @("binskim")
+ -BinskimAdditionalRunConfigParams @("IgnorePdbLoadError < True","Recurse < True")
-TsaInstanceURL $(_TsaInstanceURL)
-TsaProjectName $(_TsaProjectName)
-TsaNotificationEmail $(_TsaNotificationEmail)
diff --git a/documentation/design-docs/ipc-protocol.md b/documentation/design-docs/ipc-protocol.md
index 24fb0e5ec3..60a268c760 100644
--- a/documentation/design-docs/ipc-protocol.md
+++ b/documentation/design-docs/ipc-protocol.md
@@ -380,6 +380,9 @@ enum class ProcessCommandId : uint8_t
ResumeRuntime = 0x01,
ProcessEnvironment = 0x02,
ProcessInfo2 = 0x04,
+ EnablePerfMap = 0x05,
+ DisablePerfMap = 0x06,
+ ApplyStartupHook = 0x07
// future
}
```
@@ -845,6 +848,130 @@ struct Payload
}
```
+### `EnablePerfMap`
+
+Command Code: `0x0405`
+
+The `EnablePerfMap` command instructs the runtime to start emitting perfmap or jitdump files for the process. These files are used by the perf tool to correlate jitted code addresses in a trace.
+
+In the event of an [error](#Errors), the runtime will attempt to send an error message and subsequently close the connection.
+
+#### Inputs:
+
+Header: `{ Magic; Size; 0x0405; 0x0000 }`
+
+Payload:
+* `uint32_t perfMapType`: the type of generation to enable
+
+#### Returns (as an IPC Message Payload):
+
+Header: `{ Magic; 28; 0xFF00; 0x0000; }`
+
+`EnablePerfMap` returns:
+* `int32 hresult`: The result of enabling the perfmap or jitdump files (`0` indicates success)
+
+##### Details:
+
+Inputs:
+```c++
+enum class PerfMapType
+{
+ DISABLED = 0,
+ ALL = 1,
+ JITDUMP = 2,
+ PERFMAP = 3
+}
+
+struct Payload
+{
+ uint32_t perfMapType;
+}
+```
+
+Returns:
+```c
+Payload
+{
+ int32 hresult
+}
+```
+
+> Available since .NET 8.0
+
+### `DisablePerfMap`
+
+Command Code: `0x0406`
+
+The `DisablePerfMap` command instructs the runtime to stop emitting perfmap or jitdump files for the process. These files are used by the perf tool to correlate jitted code addresses in a trace.
+
+In the event of an [error](#Errors), the runtime will attempt to send an error message and subsequently close the connection.
+
+#### Inputs:
+
+Header: `{ Magic; Size; 0x0405; 0x0000 }`
+
+Payload: There is no payload with this command.
+
+#### Returns (as an IPC Message Payload):
+
+Header: `{ Magic; 28; 0xFF00; 0x0000; }`
+
+`DisablePerfMap` returns:
+* `int32 hresult`: The result of enabling the perfmap or jitdump files (`0` indicates success)
+
+##### Details:
+
+Returns:
+```c
+Payload
+{
+ int32 hresult
+}
+```
+
+> Available since .NET 8.0
+
+### `ApplyStartupHook`
+
+Command Code: `0x0407`
+
+The `ApplyStartupHook` command is used to provide a path to a managed assembly with a [startup hook](https://github.com/dotnet/runtime/blob/main/docs/design/features/host-startup-hook.md) to the runtime. During diagnostic suspension, the startup hook path will be added list of hooks that the runtime will execute once it has been resumed.
+
+In the event of an [error](#Errors), the runtime will attempt to send an error message and subsequently close the connection.
+
+#### Inputs:
+
+Header: `{ Magic; Size; 0x0407; 0x0000 }`
+
+* `string startupHookPath`: The path to the managed assembly that contains the startup hook implementation.
+
+#### Returns (as an IPC Message Payload):
+
+Header: `{ Magic; size; 0xFF00; 0x0000; }`
+
+`ApplyStartupHook` returns:
+* `int32 hresult`: The result of adding the startup hook (`0` indicates success)
+
+##### Details:
+
+Input:
+```
+Payload
+{
+ string startupHookPath
+}
+```
+
+Returns:
+```c++
+struct Payload
+{
+ int32 hresult
+}
+```
+
+> Available since .NET 8.0
+
## Errors
In the event an error occurs in the handling of an Ipc Message, the Diagnostic Server will attempt to send an Ipc Message encoding the error and subsequently close the connection. The connection will be closed **regardless** of the success of sending the error message. The Client is expected to be resilient in the event of a connection being abruptly closed.
diff --git a/documentation/dotnet-gcdump-instructions.md b/documentation/dotnet-gcdump-instructions.md
index 31756432e3..078785bc83 100644
--- a/documentation/dotnet-gcdump-instructions.md
+++ b/documentation/dotnet-gcdump-instructions.md
@@ -48,7 +48,7 @@ Writing gcdump to 'C:\git\diagnostics\src\Tools\dotnet-gcdump\20191023_042913_24
## Viewing the gcdump captured from dotnet-gcdump
-On Windows, `.gcdump` files can be viewed in [PerfView](https://github.com/microsoft/perfview) for analysis or in Visual Studio. There is not currently a way of opening a `.gcdump` on non-Windows platforms.
+On Windows, `.gcdump` files can be viewed in [PerfView](https://github.com/microsoft/perfview) for analysis or in Visual Studio. On non-Windows platforms, [dotnet-heapview](https://github.com/1hub/dotnet-heapview) can be used as a simple viewer.
You can collect multiple `.gcdump`s and open them simultaneously in Visual Studio to get a comparison experience.
diff --git a/documentation/tutorial/src/triggerdump/runtimeconfig.template.json b/documentation/tutorial/src/triggerdump/runtimeconfig.template.json
index f022b7ffce..8c606df890 100644
--- a/documentation/tutorial/src/triggerdump/runtimeconfig.template.json
+++ b/documentation/tutorial/src/triggerdump/runtimeconfig.template.json
@@ -1,3 +1,3 @@
{
- "rollForwardOnNoCandidateFx": 2
-}
\ No newline at end of file
+ "rollForward": "major"
+}
diff --git a/eng/InstallRuntimes.proj b/eng/InstallRuntimes.proj
index dc16301c66..9d498f1caf 100644
--- a/eng/InstallRuntimes.proj
+++ b/eng/InstallRuntimes.proj
@@ -113,13 +113,14 @@
Condition="$([MSBuild]::IsOsPlatform(Windows))"
Inputs="$(VersionsPropsPath)" Outputs="$(TestConfigFileName)">
-
+
+ IgnoreStandardErrorWarningFormat="true" Condition="'%(TestVersions.RuntimeVersion)' != ''" />
+ IgnoreStandardErrorWarningFormat="true" Condition="'%(TestVersions.AspNetVersion)' != ''" />
+
diagnostics
true
- true
diff --git a/eng/SourceBuildPrebuiltBaseline.xml b/eng/SourceBuildPrebuiltBaseline.xml
index 26918f1556..2a571b3e57 100644
--- a/eng/SourceBuildPrebuiltBaseline.xml
+++ b/eng/SourceBuildPrebuiltBaseline.xml
@@ -1,3 +1,6 @@
+
+
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 6c4edc2c12..ca13dd2841 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -1,62 +1,57 @@
-
+
https://github.com/dotnet/symstore
- 00f6edae1666690960cd207fd2b7a51232af9605
+ df78bdccafe0dca31c9e6a1b5c3cf21c33e8f9a1
-
+
https://github.com/microsoft/clrmd
- 272986369826a777686ba616a00acd48febc2546
+ c7ec730380da83d9dcb63a3d8928da701219db8e
-
+
https://github.com/microsoft/clrmd
- 272986369826a777686ba616a00acd48febc2546
+ c7ec730380da83d9dcb63a3d8928da701219db8e
-
+
https://github.com/dotnet/arcade
- 234e0726c7384ee84bf08550f2d16a1ff2d5c543
+ 385129cbc980a515ddee2fa56f6b16f3183ed9bc
-
+
https://github.com/dotnet/arcade
- 234e0726c7384ee84bf08550f2d16a1ff2d5c543
+ 385129cbc980a515ddee2fa56f6b16f3183ed9bc
https://github.com/dotnet/arcade
ccfe6da198c5f05534863bbb1bff66e830e0c6ab
-
+
https://github.com/dotnet/installer
- 18dc2cf11a2daaaa1633afd0c4225e188ce6c239
+ ec2c1ec1b16874f748cfc5d1f7da769be90e10c8
-
+
https://github.com/dotnet/aspnetcore
- c2488eead6ead7208f543d0a57104b5d167b93f9
+ 5d4e6d3812805e81a2f4ed9f2c06784204a98013
-
+
https://github.com/dotnet/aspnetcore
- c2488eead6ead7208f543d0a57104b5d167b93f9
+ 5d4e6d3812805e81a2f4ed9f2c06784204a98013
-
+
https://github.com/dotnet/runtime
- 2bf8f1aa83e192a307d5846424880cd61bec1a4f
+ 786b9872ad306d5b0febdc2e6c820b69e0e232dc
-
+
https://github.com/dotnet/runtime
- 2bf8f1aa83e192a307d5846424880cd61bec1a4f
+ 786b9872ad306d5b0febdc2e6c820b69e0e232dc
-
+
https://github.com/dotnet/source-build-reference-packages
- 4a3b4b6b37bdafe501477bf2e564380e1962ce61
+ f4903e46459e0348e3793055dd8b68b8b0264034
-
- https://github.com/dotnet/sourcelink
- 54eb3b811c57f5e94617d31a102fc9cb664ccdd5
-
-
https://github.com/dotnet/roslyn
6acaa7b7c0efea8ea292ca26888c0346fbf8b0c1
diff --git a/eng/Versions.props b/eng/Versions.props
index 23f0ae30aa..9d7d1477d2 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -16,26 +16,26 @@
- 1.0.430201
+ 1.0.442101
- 8.0.0-preview.6.23304.2
- 8.0.0-preview.6.23304.2
+ 8.0.0-rc.1.23410.15
+ 8.0.0-rc.1.23410.15
- 8.0.0-preview.6.23302.1
- 8.0.0-preview.6.23302.1
+ 8.0.0-rc.2.23422.15
+ 8.0.0-rc.2.23422.15
- 8.0.100-preview.6.23305.2
+ 8.0.100-rc.2.23420.6
- 6.0.16
+ 6.0.19
$(MicrosoftNETCoreApp60Version)
- 7.0.5
+ 7.0.10
$(MicrosoftNETCoreApp70Version)
$(MicrosoftNETCoreApp60Version)
$(MicrosoftNETCoreApp70Version)
- 8.0.0-preview.6.23302.2
+ 8.0.0-rc.1.23414.4
@@ -45,7 +45,7 @@
5.0.0
6.0.0
- 3.0.0-beta.23302.1
+ 3.0.442202
16.9.0-beta1.21055.5
3.0.7
6.0.0
@@ -61,13 +61,12 @@
4.7.2
4.7.1
2.0.3
- 8.0.0-beta.23302.3
+ 8.0.0-beta.23419.1
1.2.0-beta.406
7.0.0-beta.22316.2
10.0.18362
13.0.1
- 8.0.0-alpha.1.23302.3
- 8.0.0-beta.23252.2
+ 8.0.0-alpha.1.23421.1
3.11.0
diff --git a/eng/common/SetupNugetSources.ps1 b/eng/common/SetupNugetSources.ps1
index 6e99723945..6c65e81925 100644
--- a/eng/common/SetupNugetSources.ps1
+++ b/eng/common/SetupNugetSources.ps1
@@ -153,7 +153,7 @@ if ($dotnet31Source -ne $null) {
AddPackageSource -Sources $sources -SourceName "dotnet3.1-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v2" -Creds $creds -Username $userName -Password $Password
}
-$dotnetVersions = @('5','6','7')
+$dotnetVersions = @('5','6','7','8')
foreach ($dotnetVersion in $dotnetVersions) {
$feedPrefix = "dotnet" + $dotnetVersion;
diff --git a/eng/common/SetupNugetSources.sh b/eng/common/SetupNugetSources.sh
index 8af7d899db..d387c7eac9 100644
--- a/eng/common/SetupNugetSources.sh
+++ b/eng/common/SetupNugetSources.sh
@@ -105,7 +105,7 @@ if [ "$?" == "0" ]; then
PackageSources+=('dotnet3.1-internal-transport')
fi
-DotNetVersions=('5' '6' '7')
+DotNetVersions=('5' '6' '7' '8')
for DotNetVersion in ${DotNetVersions[@]} ; do
FeedPrefix="dotnet${DotNetVersion}";
diff --git a/eng/common/dotnet-install.sh b/eng/common/dotnet-install.sh
index abd045a324..7e69e3a9e2 100755
--- a/eng/common/dotnet-install.sh
+++ b/eng/common/dotnet-install.sh
@@ -54,6 +54,10 @@ cpuname=$(uname -m)
case $cpuname in
arm64|aarch64)
buildarch=arm64
+ if [ "$(getconf LONG_BIT)" -lt 64 ]; then
+ # This is 32-bit OS running on 64-bit CPU (for example Raspberry Pi OS)
+ buildarch=arm
+ fi
;;
loongarch64)
buildarch=loongarch64
diff --git a/eng/common/loc/P22DotNetHtmlLocalization.lss b/eng/common/loc/P22DotNetHtmlLocalization.lss
index 6661fed566..858a0b237c 100644
Binary files a/eng/common/loc/P22DotNetHtmlLocalization.lss and b/eng/common/loc/P22DotNetHtmlLocalization.lss differ
diff --git a/eng/common/native/init-compiler.sh b/eng/common/native/init-compiler.sh
index 517401b688..f5c1ec7eaf 100644
--- a/eng/common/native/init-compiler.sh
+++ b/eng/common/native/init-compiler.sh
@@ -63,7 +63,7 @@ if [ -z "$CLR_CC" ]; then
# Set default versions
if [ -z "$majorVersion" ]; then
# note: gcc (all versions) and clang versions higher than 6 do not have minor version in file name, if it is zero.
- if [ "$compiler" = "clang" ]; then versions="16 15 14 13 12 11 10 9 8 7 6.0 5.0 4.0 3.9 3.8 3.7 3.6 3.5"
+ if [ "$compiler" = "clang" ]; then versions="17 16 15 14 13 12 11 10 9 8 7 6.0 5.0 4.0 3.9 3.8 3.7 3.6 3.5"
elif [ "$compiler" = "gcc" ]; then versions="13 12 11 10 9 8 7 6 5 4.9"; fi
for version in $versions; do
diff --git a/eng/common/native/init-distro-rid.sh b/eng/common/native/init-distro-rid.sh
new file mode 100644
index 0000000000..de1687b2cc
--- /dev/null
+++ b/eng/common/native/init-distro-rid.sh
@@ -0,0 +1,130 @@
+#!/usr/bin/env bash
+
+# getNonPortableDistroRid
+#
+# Input:
+# targetOs: (str)
+# targetArch: (str)
+# rootfsDir: (str)
+#
+# Return:
+# non-portable rid
+getNonPortableDistroRid()
+{
+ local targetOs="$1"
+ local targetArch="$2"
+ local rootfsDir="$3"
+ local nonPortableRid=""
+
+ if [ "$targetOs" = "linux" ]; then
+ if [ -e "${rootfsDir}/etc/os-release" ]; then
+ source "${rootfsDir}/etc/os-release"
+
+ if [[ "${ID}" == "rhel" || "${ID}" == "rocky" || "${ID}" == "alpine" ]]; then
+ # remove the last version digit
+ VERSION_ID="${VERSION_ID%.*}"
+ fi
+
+ if [[ "${VERSION_ID:-}" =~ ^([[:digit:]]|\.)+$ ]]; then
+ nonPortableRid="${ID}.${VERSION_ID}-${targetArch}"
+ else
+ # Rolling release distros either do not set VERSION_ID, set it as blank or
+ # set it to non-version looking string (such as TEMPLATE_VERSION_ID on ArchLinux);
+ # so omit it here to be consistent with everything else.
+ nonPortableRid="${ID}-${targetArch}"
+ fi
+
+ elif [ -e "${rootfsDir}/android_platform" ]; then
+ source "$rootfsDir"/android_platform
+ nonPortableRid="$RID"
+ fi
+ fi
+
+ if [ "$targetOs" = "freebsd" ]; then
+ # $rootfsDir can be empty. freebsd-version is shell script and it should always work.
+ __freebsd_major_version=$($rootfsDir/bin/freebsd-version | { read v; echo "${v%%.*}"; })
+ nonPortableRid="freebsd.$__freebsd_major_version-${targetArch}"
+ elif command -v getprop && getprop ro.product.system.model 2>&1 | grep -qi android; then
+ __android_sdk_version=$(getprop ro.build.version.sdk)
+ nonPortableRid="android.$__android_sdk_version-${targetArch}"
+ elif [ "$targetOs" = "illumos" ]; then
+ __uname_version=$(uname -v)
+ case "$__uname_version" in
+ omnios-*)
+ __omnios_major_version=$(echo "${__uname_version:8:2}")
+ nonPortableRid=omnios."$__omnios_major_version"-"$targetArch"
+ ;;
+ joyent_*)
+ __smartos_major_version=$(echo "${__uname_version:7:4}")
+ nonPortableRid=smartos."$__smartos_major_version"-"$targetArch"
+ ;;
+ illumos_*)
+ nonPortableRid=openindiana-"$targetArch"
+ ;;
+ esac
+ elif [ "$targetOs" = "solaris" ]; then
+ __uname_version=$(uname -v)
+ __solaris_major_version=$(echo "${__uname_version%.*}")
+ nonPortableRid=solaris."$__solaris_major_version"-"$targetArch"
+ elif [ "$targetOs" = "haiku" ]; then
+ __uname_release=$(uname -r)
+ nonPortableRid=haiku.r"$__uname_release"-"$targetArch"
+ fi
+
+ echo "$(echo $nonPortableRid | tr '[:upper:]' '[:lower:]')"
+}
+
+# initDistroRidGlobal
+#
+# Input:
+# os: (str)
+# arch: (str)
+# rootfsDir?: (nullable:string)
+#
+# Return:
+# None
+#
+# Notes:
+#
+# It is important to note that the function does not return anything, but it
+# exports the following variables on success:
+#
+# __DistroRid : Non-portable rid of the target platform.
+# __PortableTargetOS : OS-part of the portable rid that corresponds to the target platform.
+#
+initDistroRidGlobal()
+{
+ local targetOs="$1"
+ local targetArch="$2"
+ local rootfsDir=""
+ if [ "$#" -ge 3 ]; then
+ rootfsDir="$3"
+ fi
+
+ if [ -n "${rootfsDir}" ]; then
+ # We may have a cross build. Check for the existence of the rootfsDir
+ if [ ! -e "${rootfsDir}" ]; then
+ echo "Error rootfsDir has been passed, but the location is not valid."
+ exit 1
+ fi
+ fi
+
+ __DistroRid=$(getNonPortableDistroRid "${targetOs}" "${targetArch}" "${rootfsDir}")
+
+ if [ -z "${__PortableTargetOS:-}" ]; then
+ __PortableTargetOS="$targetOs"
+
+ STRINGS="$(command -v strings || true)"
+ if [ -z "$STRINGS" ]; then
+ STRINGS="$(command -v llvm-strings || true)"
+ fi
+
+ # Check for musl-based distros (e.g Alpine Linux, Void Linux).
+ if "${rootfsDir}/usr/bin/ldd" --version 2>&1 | grep -q musl ||
+ ( [ -n "$STRINGS" ] && "$STRINGS" "${rootfsDir}/usr/bin/ldd" 2>&1 | grep -q musl ); then
+ __PortableTargetOS="linux-musl"
+ fi
+ fi
+
+ export __DistroRid __PortableTargetOS
+}
diff --git a/eng/common/native/init-os-and-arch.sh b/eng/common/native/init-os-and-arch.sh
new file mode 100644
index 0000000000..e693617a6c
--- /dev/null
+++ b/eng/common/native/init-os-and-arch.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+
+# Use uname to determine what the OS is.
+OSName=$(uname -s | tr '[:upper:]' '[:lower:]')
+
+if command -v getprop && getprop ro.product.system.model 2>&1 | grep -qi android; then
+ OSName="android"
+fi
+
+case "$OSName" in
+freebsd|linux|netbsd|openbsd|sunos|android|haiku)
+ os="$OSName" ;;
+darwin)
+ os=osx ;;
+*)
+ echo "Unsupported OS $OSName detected!"
+ exit 1 ;;
+esac
+
+# On Solaris, `uname -m` is discouraged, see https://docs.oracle.com/cd/E36784_01/html/E36870/uname-1.html
+# and `uname -p` returns processor type (e.g. i386 on amd64).
+# The appropriate tool to determine CPU is isainfo(1) https://docs.oracle.com/cd/E36784_01/html/E36870/isainfo-1.html.
+if [ "$os" = "sunos" ]; then
+ if uname -o 2>&1 | grep -q illumos; then
+ os="illumos"
+ else
+ os="solaris"
+ fi
+ CPUName=$(isainfo -n)
+else
+ # For the rest of the operating systems, use uname(1) to determine what the CPU is.
+ CPUName=$(uname -m)
+fi
+
+case "$CPUName" in
+ arm64|aarch64)
+ arch=arm64
+ ;;
+
+ loongarch64)
+ arch=loongarch64
+ ;;
+
+ riscv64)
+ arch=riscv64
+ ;;
+
+ amd64|x86_64)
+ arch=x64
+ ;;
+
+ armv7l|armv8l)
+ if (NAME=""; . /etc/os-release; test "$NAME" = "Tizen"); then
+ arch=armel
+ else
+ arch=arm
+ fi
+ ;;
+
+ armv6l)
+ arch=armv6
+ ;;
+
+ i[3-6]86)
+ echo "Unsupported CPU $CPUName detected, build might not succeed!"
+ arch=x86
+ ;;
+
+ s390x)
+ arch=s390x
+ ;;
+
+ ppc64le)
+ arch=ppc64le
+ ;;
+ *)
+ echo "Unknown CPU $CPUName detected!"
+ exit 1
+ ;;
+esac
diff --git a/eng/common/sdl/configure-sdl-tool.ps1 b/eng/common/sdl/configure-sdl-tool.ps1
index bdbf49e6c7..27f5a4115f 100644
--- a/eng/common/sdl/configure-sdl-tool.ps1
+++ b/eng/common/sdl/configure-sdl-tool.ps1
@@ -17,7 +17,9 @@ Param(
# Optional: Additional params to add to any tool using PoliCheck.
[string[]] $PoliCheckAdditionalRunConfigParams,
# Optional: Additional params to add to any tool using CodeQL/Semmle.
- [string[]] $CodeQLAdditionalRunConfigParams
+ [string[]] $CodeQLAdditionalRunConfigParams,
+ # Optional: Additional params to add to any tool using Binskim.
+ [string[]] $BinskimAdditionalRunConfigParams
)
$ErrorActionPreference = 'Stop'
@@ -69,22 +71,34 @@ try {
$gdnConfigFile = Join-Path $gdnConfigPath "$toolConfigName-configure.gdnconfig"
# For some tools, add default and automatic args.
- if ($tool.Name -eq 'credscan') {
- if ($targetDirectory) {
- $tool.Args += "`"TargetDirectory < $TargetDirectory`""
+ switch -Exact ($tool.Name) {
+ 'credscan' {
+ if ($targetDirectory) {
+ $tool.Args += "`"TargetDirectory < $TargetDirectory`""
+ }
+ $tool.Args += "`"OutputType < pre`""
+ $tool.Args += $CrScanAdditionalRunConfigParams
}
- $tool.Args += "`"OutputType < pre`""
- $tool.Args += $CrScanAdditionalRunConfigParams
- } elseif ($tool.Name -eq 'policheck') {
- if ($targetDirectory) {
- $tool.Args += "`"Target < $TargetDirectory`""
+ 'policheck' {
+ if ($targetDirectory) {
+ $tool.Args += "`"Target < $TargetDirectory`""
+ }
+ $tool.Args += $PoliCheckAdditionalRunConfigParams
}
- $tool.Args += $PoliCheckAdditionalRunConfigParams
- } elseif ($tool.Name -eq 'semmle' -or $tool.Name -eq 'codeql') {
- if ($targetDirectory) {
- $tool.Args += "`"SourceCodeDirectory < $TargetDirectory`""
+ {$_ -in 'semmle', 'codeql'} {
+ if ($targetDirectory) {
+ $tool.Args += "`"SourceCodeDirectory < $TargetDirectory`""
+ }
+ $tool.Args += $CodeQLAdditionalRunConfigParams
+ }
+ 'binskim' {
+ if ($targetDirectory) {
+ # Binskim crashes due to specific PDBs. GitHub issue: https://github.com/microsoft/binskim/issues/924.
+ # We are excluding all `_.pdb` files from the scan.
+ $tool.Args += "`"Target < $TargetDirectory\**;-:file|$TargetDirectory\**\_.pdb`""
+ }
+ $tool.Args += $BinskimAdditionalRunConfigParams
}
- $tool.Args += $CodeQLAdditionalRunConfigParams
}
# Create variable pointing to the args array directly so we can use splat syntax later.
diff --git a/eng/common/sdl/execute-all-sdl-tools.ps1 b/eng/common/sdl/execute-all-sdl-tools.ps1
index 4797e012c7..4715d75e97 100644
--- a/eng/common/sdl/execute-all-sdl-tools.ps1
+++ b/eng/common/sdl/execute-all-sdl-tools.ps1
@@ -35,6 +35,7 @@ Param(
[string[]] $CrScanAdditionalRunConfigParams, # Optional: Additional Params to custom build a CredScan run config in the format @("xyz:abc","sdf:1")
[string[]] $PoliCheckAdditionalRunConfigParams, # Optional: Additional Params to custom build a Policheck run config in the format @("xyz:abc","sdf:1")
[string[]] $CodeQLAdditionalRunConfigParams, # Optional: Additional Params to custom build a Semmle/CodeQL run config in the format @("xyz < abc","sdf < 1")
+ [string[]] $BinskimAdditionalRunConfigParams, # Optional: Additional Params to custom build a Binskim run config in the format @("xyz < abc","sdf < 1")
[bool] $BreakOnFailure=$False # Optional: Fail the build if there were errors during the run
)
@@ -107,7 +108,8 @@ try {
-GuardianLoggerLevel $GuardianLoggerLevel `
-CrScanAdditionalRunConfigParams $CrScanAdditionalRunConfigParams `
-PoliCheckAdditionalRunConfigParams $PoliCheckAdditionalRunConfigParams `
- -CodeQLAdditionalRunConfigParams $CodeQLAdditionalRunConfigParams
+ -CodeQLAdditionalRunConfigParams $CodeQLAdditionalRunConfigParams `
+ -BinskimAdditionalRunConfigParams $BinskimAdditionalRunConfigParams
if ($BreakOnFailure) {
Exit-IfNZEC "Sdl"
}
diff --git a/eng/common/sdl/extract-artifact-packages.ps1 b/eng/common/sdl/extract-artifact-packages.ps1
index 7f28d9c59e..f031ed5b25 100644
--- a/eng/common/sdl/extract-artifact-packages.ps1
+++ b/eng/common/sdl/extract-artifact-packages.ps1
@@ -35,31 +35,33 @@ try {
param(
[string] $PackagePath # Full path to a NuGet package
)
-
+
if (!(Test-Path $PackagePath)) {
Write-PipelineTelemetryError -Category 'Build' -Message "Input file does not exist: $PackagePath"
ExitWithExitCode 1
}
-
+
$RelevantExtensions = @('.dll', '.exe', '.pdb')
Write-Host -NoNewLine 'Extracting ' ([System.IO.Path]::GetFileName($PackagePath)) '...'
-
+
$PackageId = [System.IO.Path]::GetFileNameWithoutExtension($PackagePath)
$ExtractPath = Join-Path -Path $using:ExtractPath -ChildPath $PackageId
-
+
Add-Type -AssemblyName System.IO.Compression.FileSystem
-
+
[System.IO.Directory]::CreateDirectory($ExtractPath);
-
+
try {
$zip = [System.IO.Compression.ZipFile]::OpenRead($PackagePath)
$zip.Entries |
Where-Object {$RelevantExtensions -contains [System.IO.Path]::GetExtension($_.Name)} |
ForEach-Object {
- $TargetFile = Join-Path -Path $ExtractPath -ChildPath $_.Name
-
- [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $TargetFile, $true)
+ $TargetPath = Join-Path -Path $ExtractPath -ChildPath (Split-Path -Path $_.FullName)
+ [System.IO.Directory]::CreateDirectory($TargetPath);
+
+ $TargetFile = Join-Path -Path $ExtractPath -ChildPath $_.FullName
+ [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $TargetFile)
}
}
catch {
diff --git a/eng/common/sdl/trim-assets-version.ps1 b/eng/common/sdl/trim-assets-version.ps1
new file mode 100644
index 0000000000..a2e0048770
--- /dev/null
+++ b/eng/common/sdl/trim-assets-version.ps1
@@ -0,0 +1,75 @@
+<#
+.SYNOPSIS
+Install and run the 'Microsoft.DotNet.VersionTools.Cli' tool with the 'trim-artifacts-version' command to trim the version from the NuGet assets file name.
+
+.PARAMETER InputPath
+Full path to directory where artifact packages are stored
+
+.PARAMETER Recursive
+Search for NuGet packages recursively
+
+#>
+
+Param(
+ [string] $InputPath,
+ [bool] $Recursive = $true
+)
+
+$CliToolName = "Microsoft.DotNet.VersionTools.Cli"
+
+function Install-VersionTools-Cli {
+ param(
+ [Parameter(Mandatory=$true)][string]$Version
+ )
+
+ Write-Host "Installing the package '$CliToolName' with a version of '$version' ..."
+ $feed = "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json"
+
+ $argumentList = @("tool", "install", "--local", "$CliToolName", "--add-source $feed", "--no-cache", "--version $Version", "--create-manifest-if-needed")
+ Start-Process "$dotnet" -Verbose -ArgumentList $argumentList -NoNewWindow -Wait
+}
+
+# -------------------------------------------------------------------
+
+if (!(Test-Path $InputPath)) {
+ Write-Host "Input Path '$InputPath' does not exist"
+ ExitWithExitCode 1
+}
+
+$ErrorActionPreference = 'Stop'
+Set-StrictMode -Version 2.0
+
+$disableConfigureToolsetImport = $true
+$global:LASTEXITCODE = 0
+
+# `tools.ps1` checks $ci to perform some actions. Since the SDL
+# scripts don't necessarily execute in the same agent that run the
+# build.ps1/sh script this variable isn't automatically set.
+$ci = $true
+. $PSScriptRoot\..\tools.ps1
+
+try {
+ $dotnetRoot = InitializeDotNetCli -install:$true
+ $dotnet = "$dotnetRoot\dotnet.exe"
+
+ $toolsetVersion = Read-ArcadeSdkVersion
+ Install-VersionTools-Cli -Version $toolsetVersion
+
+ $cliToolFound = (& "$dotnet" tool list --local | Where-Object {$_.Split(' ')[0] -eq $CliToolName})
+ if ($null -eq $cliToolFound) {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "The '$CliToolName' tool is not installed."
+ ExitWithExitCode 1
+ }
+
+ Exec-BlockVerbosely {
+ & "$dotnet" $CliToolName trim-assets-version `
+ --assets-path $InputPath `
+ --recursive $Recursive
+ Exit-IfNZEC "Sdl"
+ }
+}
+catch {
+ Write-Host $_
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_
+ ExitWithExitCode 1
+}
\ No newline at end of file
diff --git a/eng/common/templates/job/execute-sdl.yml b/eng/common/templates/job/execute-sdl.yml
index 7aabaa1801..7870f93bc1 100644
--- a/eng/common/templates/job/execute-sdl.yml
+++ b/eng/common/templates/job/execute-sdl.yml
@@ -105,6 +105,11 @@ jobs:
downloadPath: $(Build.ArtifactStagingDirectory)\artifacts
checkDownloadedFiles: true
+ - powershell: eng/common/sdl/trim-assets-version.ps1
+ -InputPath $(Build.ArtifactStagingDirectory)\artifacts
+ displayName: Trim the version from the NuGet packages
+ continueOnError: ${{ parameters.sdlContinueOnError }}
+
- powershell: eng/common/sdl/extract-artifact-packages.ps1
-InputPath $(Build.ArtifactStagingDirectory)\artifacts\BlobArtifacts
-ExtractPath $(Build.ArtifactStagingDirectory)\artifacts\BlobArtifacts
diff --git a/eng/common/templates/steps/execute-sdl.yml b/eng/common/templates/steps/execute-sdl.yml
index 9dd5709f66..07426fde05 100644
--- a/eng/common/templates/steps/execute-sdl.yml
+++ b/eng/common/templates/steps/execute-sdl.yml
@@ -33,7 +33,7 @@ steps:
- ${{ if ne(parameters.overrideParameters, '') }}:
- powershell: ${{ parameters.executeAllSdlToolsScript }} ${{ parameters.overrideParameters }}
- displayName: Execute SDL
+ displayName: Execute SDL (Overridden)
continueOnError: ${{ parameters.sdlContinueOnError }}
condition: ${{ parameters.condition }}
diff --git a/eng/common/templates/steps/source-build.yml b/eng/common/templates/steps/source-build.yml
index 1100521834..41bbb91573 100644
--- a/eng/common/templates/steps/source-build.yml
+++ b/eng/common/templates/steps/source-build.yml
@@ -118,3 +118,12 @@ steps:
artifactName: BuildLogs_SourceBuild_${{ parameters.platform.name }}_Attempt$(System.JobAttempt)
continueOnError: true
condition: succeededOrFailed()
+
+# Manually inject component detection so that we can ignore the source build upstream cache, which contains
+# a nupkg cache of input packages (a local feed).
+# This path must match the upstream cache path in property 'CurrentRepoSourceBuiltNupkgCacheDir'
+# in src\Microsoft.DotNet.Arcade.Sdk\tools\SourceBuild\SourceBuildArcade.targets
+- task: ComponentGovernanceComponentDetection@0
+ displayName: Component Detection (Exclude upstream cache)
+ inputs:
+ ignoreDirectories: '$(Build.SourcesDirectory)/artifacts/source-build/self/src/artifacts/obj/source-built-upstream-cache'
diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1
index ffe0b4e2df..aa74ab4a81 100644
--- a/eng/common/tools.ps1
+++ b/eng/common/tools.ps1
@@ -379,7 +379,7 @@ function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements =
}
# Minimum VS version to require.
- $vsMinVersionReqdStr = '16.8'
+ $vsMinVersionReqdStr = '17.6'
$vsMinVersionReqd = [Version]::new($vsMinVersionReqdStr)
# If the version of msbuild is going to be xcopied,
@@ -671,6 +671,10 @@ function InitializeNativeTools() {
}
}
+function Read-ArcadeSdkVersion() {
+ return $GlobalJson.'msbuild-sdks'.'Microsoft.DotNet.Arcade.Sdk'
+}
+
function InitializeToolset() {
if (Test-Path variable:global:_ToolsetBuildProj) {
return $global:_ToolsetBuildProj
@@ -678,7 +682,7 @@ function InitializeToolset() {
$nugetCache = GetNuGetPackageCachePath
- $toolsetVersion = $GlobalJson.'msbuild-sdks'.'Microsoft.DotNet.Arcade.Sdk'
+ $toolsetVersion = Read-ArcadeSdkVersion
$toolsetLocationFile = Join-Path $ToolsetDir "$toolsetVersion.txt"
if (Test-Path $toolsetLocationFile) {
diff --git a/global.json b/global.json
index d3ebd457b7..b9885f3713 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"tools": {
- "dotnet": "8.0.100-preview.4.23260.5",
+ "dotnet": "8.0.100-preview.7.23376.3",
"runtimes": {
"dotnet": [
"$(MicrosoftNETCoreApp60Version)",
@@ -16,6 +16,6 @@
},
"msbuild-sdks": {
"Microsoft.Build.NoTargets": "3.5.0",
- "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23302.3"
+ "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23419.1"
}
}
diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/Runtime.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/Runtime.cs
index 771e0d14c2..04325022be 100644
--- a/src/Microsoft.Diagnostics.DebugServices.Implementation/Runtime.cs
+++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/Runtime.cs
@@ -22,6 +22,7 @@ public class Runtime : IRuntime, IDisposable
private readonly ClrInfo _clrInfo;
private readonly ISymbolService _symbolService;
private Version _runtimeVersion;
+ private ClrRuntime _clrRuntime;
private string _dacFilePath;
private string _dbiFilePath;
@@ -56,12 +57,10 @@ public Runtime(IServiceProvider services, int id, ClrInfo clrInfo)
void IDisposable.Dispose()
{
- if (_serviceContainer.TryGetCachedService(typeof(ClrRuntime), out object service))
- {
- // The DataTarget created in the RuntimeProvider is disposed here. The ClrRuntime
- // instance is disposed below in DisposeServices().
- ((ClrRuntime)service).DataTarget.Dispose();
- }
+ // The DataTarget created in the RuntimeProvider is disposed here. The ClrRuntime
+ // instance is disposed below in DisposeServices().
+ _clrRuntime?.DataTarget.Dispose();
+ _clrRuntime = null;
_serviceContainer.RemoveService(typeof(IRuntime));
_serviceContainer.DisposeServices();
}
@@ -125,7 +124,7 @@ private ClrRuntime CreateRuntime()
{
// Ignore the DAC version mismatch that can happen because the clrmd ELF dump reader
// returns 0.0.0.0 for the runtime module that the DAC is matched against.
- return _clrInfo.CreateRuntime(dacFilePath, ignoreMismatch: true);
+ return _clrRuntime = _clrInfo.CreateRuntime(dacFilePath, ignoreMismatch: true);
}
catch (Exception ex) when
(ex is DllNotFoundException or
diff --git a/src/Microsoft.Diagnostics.DebugServices/ServiceContainer.cs b/src/Microsoft.Diagnostics.DebugServices/ServiceContainer.cs
index d51b4d8cab..9b497c53fe 100644
--- a/src/Microsoft.Diagnostics.DebugServices/ServiceContainer.cs
+++ b/src/Microsoft.Diagnostics.DebugServices/ServiceContainer.cs
@@ -73,30 +73,18 @@ public void DisposeServices()
}
///
- /// Get the cached/instantiated service instance if one exists. Don't call the factory or parent to create.
+ /// Returns the instance of the service or returns null if service doesn't exist
///
/// service type
- /// service instance (can be null)
- /// if true, found service
- public bool TryGetCachedService(Type type, out object service)
+ /// service instance or null
+ public object GetService(Type type)
{
Debug.Assert(type != null);
if (type == typeof(IServiceProvider))
{
- service = this;
- return true;
+ return this;
}
- return _instances.TryGetValue(type, out service);
- }
-
- ///
- /// Returns the instance of the service or returns null if service doesn't exist
- ///
- /// service type
- /// service instance or null
- public object GetService(Type type)
- {
- if (TryGetCachedService(type, out object service))
+ if (_instances.TryGetValue(type, out object service))
{
return service;
}
diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpExceptionsCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpExceptionsCommand.cs
new file mode 100644
index 0000000000..4f57cf3897
--- /dev/null
+++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpExceptionsCommand.cs
@@ -0,0 +1,122 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using Microsoft.Diagnostics.DebugServices;
+using Microsoft.Diagnostics.ExtensionCommands.Output;
+using Microsoft.Diagnostics.Runtime;
+
+#nullable enable
+
+namespace Microsoft.Diagnostics.ExtensionCommands
+{
+ [Command(Name = "dumpexceptions", Help = "Displays a list of all managed exceptions.")]
+ public class DumpExceptionsCommand : CommandBase
+ {
+ [ServiceImport]
+ public ClrRuntime Runtime { get; set; } = null!;
+
+ [ServiceImport]
+ public LiveObjectService LiveObjects { get; set; } = null!;
+
+ [Option(Name = "-live")]
+ public bool Live { get; set; }
+
+ [Option(Name = "-dead")]
+ public bool Dead{ get; set; }
+
+ [Option(Name = "-gen")]
+ public string? Generation { get; set; }
+
+ [Option(Name = "-type")]
+ public string? Type { get; set; }
+
+ public override void Invoke()
+ {
+ HeapWithFilters filteredHeap = ParseArguments();
+
+ IEnumerable exceptionObjects =
+ filteredHeap.EnumerateFilteredObjects(Console.CancellationToken)
+ .Where(obj => obj.IsException);
+
+ if (Live)
+ {
+ exceptionObjects = exceptionObjects.Where(obj => LiveObjects.IsLive(obj));
+ }
+
+ if (Dead)
+ {
+ exceptionObjects = exceptionObjects.Where(obj => !LiveObjects.IsLive(obj));
+ }
+
+ if (!string.IsNullOrWhiteSpace(Type))
+ {
+ string type = Type!;
+ exceptionObjects = exceptionObjects.Where(obj => obj.Type!.Name!.IndexOf(type, StringComparison.OrdinalIgnoreCase) >= 0);
+ }
+
+ PrintExceptions(exceptionObjects);
+ }
+
+ private void PrintExceptions(IEnumerable exceptionObjects)
+ {
+ Table output = new(Console, ColumnKind.Pointer, ColumnKind.Pointer, ColumnKind.TypeName);
+ output.WriteHeader("Address", "MethodTable", "Message", "Name");
+
+ int totalExceptions = 0;
+ foreach (ClrObject exceptionObject in exceptionObjects)
+ {
+ totalExceptions++;
+
+ ClrException clrException = exceptionObject.AsException()!;
+ output.WriteRow(exceptionObject.Address, exceptionObject.Type!.MethodTable, exceptionObject.Type!.Name);
+
+ Console.Write(" Message: ");
+ Console.WriteLine(clrException.Message ?? "");
+
+ ImmutableArray stackTrace = clrException.StackTrace;
+ if (stackTrace.Length > 0)
+ {
+ Console.Write(" StackFrame: ");
+ Console.WriteLine(stackTrace[0].ToString());
+ }
+ }
+
+ Console.WriteLine();
+ Console.WriteLine($" Total: {totalExceptions} objects");
+ }
+
+ private HeapWithFilters ParseArguments()
+ {
+ HeapWithFilters filteredHeap = new(Runtime.Heap);
+
+ if (Live && Dead)
+ {
+ Live = false;
+ Dead = false;
+ }
+
+ // TODO: CR: this is the same as in dumpheap. Where to put this?
+ if (!string.IsNullOrWhiteSpace(Generation))
+ {
+ Generation generation = Generation!.ToLowerInvariant() switch
+ {
+ "gen0" => Diagnostics.Runtime.Generation.Generation0,
+ "gen1" => Diagnostics.Runtime.Generation.Generation1,
+ "gen2" => Diagnostics.Runtime.Generation.Generation2,
+ "loh" or "large" => Diagnostics.Runtime.Generation.Large,
+ "poh" or "pinned" => Diagnostics.Runtime.Generation.Pinned,
+ "foh" or "frozen" => Diagnostics.Runtime.Generation.Frozen,
+ _ => throw new ArgumentException($"Unknown generation: {Generation}. Only gen0, gen1, gen2, loh (large), poh (pinned) and foh (frozen) are supported")
+ };
+
+ filteredHeap.Generation = generation;
+ }
+
+ return filteredHeap;
+ }
+ }
+}
diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapCommand.cs
index 2f8c47256b..5f2faf6549 100644
--- a/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapCommand.cs
+++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpHeapCommand.cs
@@ -62,6 +62,9 @@ public class DumpHeapCommand : CommandBase
[Option(Name = "-thinlock")]
public bool ThinLock { get; set; }
+ [Option(Name = "-gen")]
+ public string Generation { get; set; }
+
[Argument(Help = "Optional memory ranges in the form of: [Start [End]]")]
public string[] MemoryRange { get; set; }
@@ -227,6 +230,22 @@ private void ParseArguments()
MethodTable = Runtime.Heap.StringType.MethodTable;
}
+ if (!string.IsNullOrWhiteSpace(Generation))
+ {
+ Generation generation = Generation.ToLowerInvariant() switch
+ {
+ "gen0" => Diagnostics.Runtime.Generation.Generation0,
+ "gen1" => Diagnostics.Runtime.Generation.Generation1,
+ "gen2" => Diagnostics.Runtime.Generation.Generation2,
+ "loh" or "large" => Diagnostics.Runtime.Generation.Large,
+ "poh" or "pinned" => Diagnostics.Runtime.Generation.Pinned,
+ "foh" or "frozen" => Diagnostics.Runtime.Generation.Frozen,
+ _ => throw new ArgumentException($"Unknown generation: {Generation}. Only gen0, gen1, gen2, loh (large), poh (pinned) and foh (frozen) are supported")
+ };
+
+ FilteredHeap.Generation = generation;
+ }
+
FilteredHeap.SortSegments = (seg) => seg.OrderBy(seg => seg.Start);
}
}
diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/HeapWithFilters.cs b/src/Microsoft.Diagnostics.ExtensionCommands/HeapWithFilters.cs
index 7c5604e6b1..b8abc37782 100644
--- a/src/Microsoft.Diagnostics.ExtensionCommands/HeapWithFilters.cs
+++ b/src/Microsoft.Diagnostics.ExtensionCommands/HeapWithFilters.cs
@@ -63,6 +63,11 @@ public int? GCHeap
///
public ulong MaximumObjectSize { get; set; }
+ ///
+ /// Only enumerate object from this generation
+ ///
+ public Generation? Generation { get; set; }
+
///
/// The order in which to enumerate segments. This also applies to object enumeration.
///
@@ -228,6 +233,11 @@ public IEnumerable EnumerateFilteredObjects(CancellationToken cancell
objs = segment.EnumerateObjects(carefully: true);
}
+ if (Generation is Generation generation)
+ {
+ objs = objs.Where(obj => segment.GetGeneration(obj) == generation);
+ }
+
foreach (ClrObject obj in objs)
{
cancellation.ThrowIfCancellationRequested();
diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Output/ColumnKind.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Output/ColumnKind.cs
index aeaae671c7..aedc751b52 100644
--- a/src/Microsoft.Diagnostics.ExtensionCommands/Output/ColumnKind.cs
+++ b/src/Microsoft.Diagnostics.ExtensionCommands/Output/ColumnKind.cs
@@ -9,6 +9,8 @@ internal static class ColumnKind
{
private static Column? s_pointer;
private static Column? s_text;
+ private static Column? s_image;
+ private static Column? s_typeName;
private static Column? s_hexOffset;
private static Column? s_hexValue;
private static Column? s_dumpObj;
@@ -96,13 +98,13 @@ internal static class ColumnKind
/// name instead of truncating based on alignment. This ensures the most important part of the name (the
/// actual type name) is preserved instead of the namespace.
///
- public static Column TypeName => s_text ??= new(Align.Left, -1, Formats.TypeName);
+ public static Column TypeName => s_typeName ??= new(Align.Left, -1, Formats.TypeName);
///
/// A path to an image on disk. Note that images are always truncted by removing the beginning of the image's
/// path instead of the end, preserving the filename.
///
- public static Column Image => s_text ??= new(Align.Left, -1, Formats.Image);
+ public static Column Image => s_image ??= new(Align.Left, -1, Formats.Image);
///
/// A MemoryRange printed as "[start-end]".
diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs
index effbdba926..3becf63e73 100644
--- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs
+++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs
@@ -30,7 +30,10 @@ public sealed class MetricEventPipeProvider
public sealed class MetricSourceConfiguration : MonitoringSourceConfiguration
{
+ private const string SharedSessionId = "SHARED";
+
private readonly IList _eventPipeProviders;
+ public string ClientId { get; private set; }
public string SessionId { get; private set; }
public MetricSourceConfiguration(float metricIntervalSeconds, IEnumerable eventCounterProviderNames)
@@ -38,7 +41,7 @@ public MetricSourceConfiguration(float metricIntervalSeconds, IEnumerable providers, int maxHistograms = 20, int maxTimeSeries = 1000)
+ public MetricSourceConfiguration(float metricIntervalSeconds, IEnumerable providers, int maxHistograms = 20, int maxTimeSeries = 1000, bool useSharedSession = false)
{
if (providers == null)
{
@@ -65,7 +68,10 @@ public MetricSourceConfiguration(float metricIntervalSeconds, IEnumerable p.Provider));
- SessionId = Guid.NewGuid().ToString();
+ ClientId = Guid.NewGuid().ToString();
+
+ // Shared Session Id was added in 8.0 - older runtimes will not properly support it.
+ SessionId = useSharedSession ? SharedSessionId : Guid.NewGuid().ToString();
EventPipeProvider metricsEventSourceProvider =
new(MonitoringSourceConfiguration.SystemDiagnosticsMetricsProviderName, EventLevel.Informational, TimeSeriesValuesEventKeyword,
@@ -75,7 +81,8 @@ public MetricSourceConfiguration(float metricIntervalSeconds, IEnumerable
{
private readonly IEnumerable _loggers;
private readonly CounterFilter _filter;
+ private string _clientId;
private string _sessionId;
public MetricsPipeline(DiagnosticsClient client,
@@ -45,8 +46,9 @@ protected override MonitoringSourceConfiguration CreateConfiguration()
IntervalSeconds = counterGroup.IntervalSeconds,
Type = (MetricType)counterGroup.Type
}),
- Settings.MaxHistograms, Settings.MaxTimeSeries);
+ Settings.MaxHistograms, Settings.MaxTimeSeries, useSharedSession: Settings.UseSharedSession);
+ _clientId = config.ClientId;
_sessionId = config.SessionId;
return config;
@@ -59,7 +61,7 @@ protected override async Task OnEventSourceAvailable(EventPipeEventSource eventS
eventSource.Dynamic.All += traceEvent => {
try
{
- if (traceEvent.TryGetCounterPayload(_filter, _sessionId, out ICounterPayload counterPayload))
+ if (traceEvent.TryGetCounterPayload(_filter, _sessionId, _clientId, out ICounterPayload counterPayload))
{
ExecuteCounterLoggerAction((metricLogger) => metricLogger.Log(counterPayload));
}
diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/MetricsPipelineSettings.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/MetricsPipelineSettings.cs
index 48d705dd5a..4e9c4f83f4 100644
--- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/MetricsPipelineSettings.cs
+++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/MetricsPipelineSettings.cs
@@ -16,6 +16,8 @@ internal class MetricsPipelineSettings : EventSourcePipelineSettings
public int MaxHistograms { get; set; }
public int MaxTimeSeries { get; set; }
+
+ public bool UseSharedSession { get; set; }
}
[Flags]
diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs
index 347a4e11f2..942a7ebddf 100644
--- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs
+++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs
@@ -4,13 +4,16 @@
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.Text;
using Microsoft.Diagnostics.Tracing;
namespace Microsoft.Diagnostics.Monitoring.EventPipe
{
internal static class TraceEventExtensions
{
- public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilter filter, string sessionId, out ICounterPayload payload)
+ private static HashSet inactiveSharedSessions = new(StringComparer.OrdinalIgnoreCase);
+
+ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilter filter, string sessionId, string clientId, out ICounterPayload payload)
{
payload = null;
@@ -71,7 +74,7 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte
return true;
}
- if (sessionId != null && MonitoringSourceConfiguration.SystemDiagnosticsMetricsProviderName.Equals(traceEvent.ProviderName))
+ if (clientId != null && !inactiveSharedSessions.Contains(clientId) && MonitoringSourceConfiguration.SystemDiagnosticsMetricsProviderName.Equals(traceEvent.ProviderName))
{
if (traceEvent.EventName == "BeginInstrumentReporting")
{
@@ -114,6 +117,10 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte
{
HandleMultipleSessionsNotSupportedError(traceEvent, sessionId, out payload);
}
+ else if (traceEvent.EventName == "MultipleSessionsConfiguredIncorrectlyError")
+ {
+ HandleMultipleSessionsConfiguredIncorrectlyError(traceEvent, clientId, out payload);
+ }
return payload != null;
}
@@ -299,7 +306,7 @@ private static void HandleError(TraceEvent obj, string sessionId, out ICounterPa
string payloadSessionId = (string)obj.PayloadValue(0);
string error = (string)obj.PayloadValue(1);
- if (sessionId != payloadSessionId)
+ if (payloadSessionId != sessionId)
{
return;
}
@@ -322,13 +329,66 @@ private static void HandleMultipleSessionsNotSupportedError(TraceEvent obj, stri
}
else
{
- string errorMessage = "Error: Another metrics collection session is already in progress for the target process, perhaps from another tool? " + Environment.NewLine +
+ string errorMessage = "Error: Another metrics collection session is already in progress for the target process." + Environment.NewLine +
"Concurrent sessions are not supported.";
payload = new ErrorPayload(errorMessage, obj.TimeStamp);
}
}
+ internal static bool TryCreateSharedSessionConfiguredIncorrectlyMessage(TraceEvent obj, string clientId, out string message)
+ {
+ message = string.Empty;
+
+ string payloadSessionId = (string)obj.PayloadValue(0);
+
+ if (payloadSessionId != clientId)
+ {
+ // If our session is not the one that is running then the error is not for us,
+ // it is for some other session that came later
+ return false;
+ }
+
+ string expectedMaxHistograms = (string)obj.PayloadValue(1);
+ string actualMaxHistograms = (string)obj.PayloadValue(2);
+ string expectedMaxTimeSeries = (string)obj.PayloadValue(3);
+ string actualMaxTimeSeries = (string)obj.PayloadValue(4);
+ string expectedRefreshInterval = (string)obj.PayloadValue(5);
+ string actualRefreshInterval = (string)obj.PayloadValue(6);
+
+ StringBuilder errorMessage = new("Error: Another shared metrics collection session is already in progress for the target process." + Environment.NewLine +
+ "To enable this metrics session alongside the existing session, update the following values:" + Environment.NewLine);
+
+ if (expectedMaxHistograms != actualMaxHistograms)
+ {
+ errorMessage.Append($"MaxHistograms: {expectedMaxHistograms}" + Environment.NewLine);
+ }
+ if (expectedMaxTimeSeries != actualMaxTimeSeries)
+ {
+ errorMessage.Append($"MaxTimeSeries: {expectedMaxTimeSeries}" + Environment.NewLine);
+ }
+ if (expectedRefreshInterval != actualRefreshInterval)
+ {
+ errorMessage.Append($"IntervalSeconds: {expectedRefreshInterval}" + Environment.NewLine);
+ }
+
+ message = errorMessage.ToString();
+
+ return true;
+ }
+
+ private static void HandleMultipleSessionsConfiguredIncorrectlyError(TraceEvent obj, string clientId, out ICounterPayload payload)
+ {
+ payload = null;
+
+ if (TryCreateSharedSessionConfiguredIncorrectlyMessage(obj, clientId, out string message))
+ {
+ payload = new ErrorPayload(message.ToString(), obj.TimeStamp);
+
+ inactiveSharedSessions.Add(clientId);
+ }
+ }
+
private static void HandleObservableInstrumentCallbackError(TraceEvent obj, string sessionId, out ICounterPayload payload)
{
payload = null;
diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Microsoft.Diagnostics.Monitoring.EventPipe.csproj b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Microsoft.Diagnostics.Monitoring.EventPipe.csproj
index aef58a9d4f..0682848f12 100644
--- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Microsoft.Diagnostics.Monitoring.EventPipe.csproj
+++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Microsoft.Diagnostics.Monitoring.EventPipe.csproj
@@ -39,6 +39,7 @@
+
diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/EventCounter/EventCounterTrigger.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/EventCounter/EventCounterTrigger.cs
index a41580f7a1..6350d43038 100644
--- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/EventCounter/EventCounterTrigger.cs
+++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/EventCounter/EventCounterTrigger.cs
@@ -58,7 +58,7 @@ public IReadOnlyDictionary> GetProviderEvent
public bool HasSatisfiedCondition(TraceEvent traceEvent)
{
// Filter to the counter of interest before forwarding to the implementation
- if (traceEvent.TryGetCounterPayload(_filter, null, out ICounterPayload payload))
+ if (traceEvent.TryGetCounterPayload(_filter, null, null, out ICounterPayload payload))
{
return _impl.HasSatisfiedCondition(payload);
}
diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/SystemDiagnosticsMetricsTrigger/SystemDiagnosticsMetricsTrigger.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/SystemDiagnosticsMetricsTrigger/SystemDiagnosticsMetricsTrigger.cs
index 20331b09d4..378e389065 100644
--- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/SystemDiagnosticsMetricsTrigger/SystemDiagnosticsMetricsTrigger.cs
+++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/SystemDiagnosticsMetricsTrigger/SystemDiagnosticsMetricsTrigger.cs
@@ -27,6 +27,7 @@ internal sealed class SystemDiagnosticsMetricsTrigger :
private readonly CounterFilter _filter;
private readonly SystemDiagnosticsMetricsTriggerImpl _impl;
private readonly string _meterName;
+ private readonly string _clientId;
private readonly string _sessionId;
public SystemDiagnosticsMetricsTrigger(SystemDiagnosticsMetricsTriggerSettings settings)
@@ -45,6 +46,8 @@ public SystemDiagnosticsMetricsTrigger(SystemDiagnosticsMetricsTriggerSettings s
_meterName = settings.MeterName;
+ _clientId = settings.ClientId;
+
_sessionId = settings.SessionId;
}
@@ -56,7 +59,7 @@ public IReadOnlyDictionary> GetProviderEvent
public bool HasSatisfiedCondition(TraceEvent traceEvent)
{
// Filter to the counter of interest before forwarding to the implementation
- if (traceEvent.TryGetCounterPayload(_filter, _sessionId, out ICounterPayload payload))
+ if (traceEvent.TryGetCounterPayload(_filter, _sessionId, _clientId, out ICounterPayload payload))
{
return _impl.HasSatisfiedCondition(payload);
}
@@ -71,7 +74,9 @@ public static MetricSourceConfiguration CreateConfiguration(SystemDiagnosticsMet
settings.CounterIntervalSeconds,
MetricSourceConfiguration.CreateProviders(new string[] { settings.MeterName }, MetricType.Meter),
settings.MaxHistograms,
- settings.MaxTimeSeries);
+ settings.MaxTimeSeries,
+ useSharedSession: settings.UseSharedSession);
+ settings.ClientId = config.ClientId;
settings.SessionId = config.SessionId;
return config;
diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/SystemDiagnosticsMetricsTrigger/SystemDiagnosticsMetricsTriggerSettings.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/SystemDiagnosticsMetricsTrigger/SystemDiagnosticsMetricsTriggerSettings.cs
index 405059a736..08c0dc2b7d 100644
--- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/SystemDiagnosticsMetricsTrigger/SystemDiagnosticsMetricsTriggerSettings.cs
+++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/SystemDiagnosticsMetricsTrigger/SystemDiagnosticsMetricsTriggerSettings.cs
@@ -62,8 +62,12 @@ internal sealed class SystemDiagnosticsMetricsTriggerSettings :
public int MaxTimeSeries { get; set; }
+ public string ClientId { get; set; }
+
public string SessionId { get; set; }
+ public bool UseSharedSession { get; set; }
+
IEnumerable IValidatableObject.Validate(ValidationContext validationContext)
{
return SharedTriggerSettingsValidation.Validate(GreaterThan, LessThan);
diff --git a/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClient/DiagnosticsClient.cs b/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClient/DiagnosticsClient.cs
index 8a98866293..8084d0af8e 100644
--- a/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClient/DiagnosticsClient.cs
+++ b/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClient/DiagnosticsClient.cs
@@ -298,6 +298,55 @@ internal async Task> GetProcessEnvironmentAsync(Cance
return await helper.ReadEnvironmentAsync(response.Continuation, token).ConfigureAwait(false);
}
+ internal void ApplyStartupHook(string startupHookPath)
+ {
+ IpcMessage message = CreateApplyStartupHookMessage(startupHookPath);
+ IpcMessage response = IpcClient.SendMessage(_endpoint, message);
+ ValidateResponseMessage(response, nameof(ApplyStartupHook));
+ }
+
+ internal async Task ApplyStartupHookAsync(string startupHookPath, CancellationToken token)
+ {
+ IpcMessage message = CreateApplyStartupHookMessage(startupHookPath);
+ IpcMessage response = await IpcClient.SendMessageAsync(_endpoint, message, token).ConfigureAwait(false);
+ ValidateResponseMessage(response, nameof(ApplyStartupHookAsync));
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public void EnablePerfMap(PerfMapType type)
+ {
+ IpcMessage request = CreateEnablePerfMapMessage(type);
+ IpcMessage response = IpcClient.SendMessage(_endpoint, request);
+ ValidateResponseMessage(response, nameof(EnablePerfMap));
+ }
+
+ internal async Task EnablePerfMapAsync(PerfMapType type, CancellationToken token)
+ {
+ IpcMessage request = CreateEnablePerfMapMessage(type);
+ IpcMessage response = await IpcClient.SendMessageAsync(_endpoint, request, token).ConfigureAwait(false);
+ ValidateResponseMessage(response, nameof(EnablePerfMapAsync));
+ }
+
+ ///
+ ///
+ ///
+ public void DisablePerfMap()
+ {
+ IpcMessage request = CreateDisablePerfMapMessage();
+ IpcMessage response = IpcClient.SendMessage(_endpoint, request);
+ ValidateResponseMessage(response, nameof(DisablePerfMap));
+ }
+
+ internal async Task DisablePerfMapAsync(CancellationToken token)
+ {
+ IpcMessage request = CreateDisablePerfMapMessage();
+ IpcMessage response = await IpcClient.SendMessageAsync(_endpoint, request, token).ConfigureAwait(false);
+ ValidateResponseMessage(response, nameof(DisablePerfMapAsync));
+ }
+
///
/// Get all the active processes that can be attached to.
///
@@ -355,8 +404,15 @@ static IEnumerable GetAllPublishedProcesses(string[] files)
internal ProcessInfo GetProcessInfo()
{
+ // Attempt to get ProcessInfo v3
+ ProcessInfo processInfo = TryGetProcessInfo3();
+ if (null != processInfo)
+ {
+ return processInfo;
+ }
+
// Attempt to get ProcessInfo v2
- ProcessInfo processInfo = TryGetProcessInfo2();
+ processInfo = TryGetProcessInfo2();
if (null != processInfo)
{
return processInfo;
@@ -369,8 +425,15 @@ internal ProcessInfo GetProcessInfo()
internal async Task GetProcessInfoAsync(CancellationToken token)
{
+ // Attempt to get ProcessInfo v3
+ ProcessInfo processInfo = await TryGetProcessInfo3Async(token).ConfigureAwait(false);
+ if (null != processInfo)
+ {
+ return processInfo;
+ }
+
// Attempt to get ProcessInfo v2
- ProcessInfo processInfo = await TryGetProcessInfo2Async(token).ConfigureAwait(false);
+ processInfo = await TryGetProcessInfo2Async(token).ConfigureAwait(false);
if (null != processInfo)
{
return processInfo;
@@ -395,6 +458,20 @@ private async Task TryGetProcessInfo2Async(CancellationToken token)
return TryGetProcessInfo2FromResponse(response2, nameof(GetProcessInfoAsync));
}
+ private ProcessInfo TryGetProcessInfo3()
+ {
+ IpcMessage request = CreateProcessInfo3Message();
+ using IpcResponse response2 = IpcClient.SendMessageGetContinuation(_endpoint, request);
+ return TryGetProcessInfo3FromResponse(response2, nameof(GetProcessInfo));
+ }
+
+ private async Task TryGetProcessInfo3Async(CancellationToken token)
+ {
+ IpcMessage request = CreateProcessInfo3Message();
+ using IpcResponse response2 = await IpcClient.SendMessageGetContinuationAsync(_endpoint, request, token).ConfigureAwait(false);
+ return TryGetProcessInfo3FromResponse(response2, nameof(GetProcessInfoAsync));
+ }
+
private static byte[] SerializePayload(T arg)
{
using (MemoryStream stream = new())
@@ -522,6 +599,11 @@ private static IpcMessage CreateProcessInfo2Message()
return new IpcMessage(DiagnosticsServerCommandSet.Process, (byte)ProcessCommandId.GetProcessInfo2);
}
+ private static IpcMessage CreateProcessInfo3Message()
+ {
+ return new IpcMessage(DiagnosticsServerCommandSet.Process, (byte)ProcessCommandId.GetProcessInfo3);
+ }
+
private static IpcMessage CreateResumeRuntimeMessage()
{
return new IpcMessage(DiagnosticsServerCommandSet.Process, (byte)ProcessCommandId.ResumeRuntime);
@@ -576,6 +658,29 @@ private static IpcMessage CreateWriteDumpMessage(DumpCommandId command, DumpType
return new IpcMessage(DiagnosticsServerCommandSet.Dump, (byte)command, payload);
}
+ private static IpcMessage CreateApplyStartupHookMessage(string startupHookPath)
+ {
+ if (string.IsNullOrEmpty(startupHookPath))
+ {
+ throw new ArgumentException($"{nameof(startupHookPath)} required");
+ }
+
+ byte[] serializedConfiguration = SerializePayload(startupHookPath);
+
+ return new IpcMessage(DiagnosticsServerCommandSet.Process, (byte)ProcessCommandId.ApplyStartupHook, serializedConfiguration);
+ }
+
+ private static IpcMessage CreateEnablePerfMapMessage(PerfMapType type)
+ {
+ byte[] payload = SerializePayload((uint)type);
+ return new IpcMessage(DiagnosticsServerCommandSet.Process, (byte)ProcessCommandId.EnablePerfMap, payload);
+ }
+
+ private static IpcMessage CreateDisablePerfMapMessage()
+ {
+ return new IpcMessage(DiagnosticsServerCommandSet.Process, (byte)ProcessCommandId.DisablePerfMap);
+ }
+
private static ProcessInfo GetProcessInfoFromResponse(IpcResponse response, string operationName)
{
ValidateResponseMessage(response.Message, operationName);
@@ -593,6 +698,16 @@ private static ProcessInfo TryGetProcessInfo2FromResponse(IpcResponse response,
return ProcessInfo.ParseV2(response.Message.Payload);
}
+ private static ProcessInfo TryGetProcessInfo3FromResponse(IpcResponse response, string operationName)
+ {
+ if (!ValidateResponseMessage(response.Message, operationName, ValidateResponseOptions.UnknownCommandReturnsFalse))
+ {
+ return null;
+ }
+
+ return ProcessInfo.ParseV3(response.Message.Payload);
+ }
+
internal static bool ValidateResponseMessage(IpcMessage responseMessage, string operationName, ValidateResponseOptions options = ValidateResponseOptions.None)
{
switch ((DiagnosticsServerResponseId)responseMessage.Header.CommandId)
diff --git a/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClient/PerfMapType.cs b/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClient/PerfMapType.cs
new file mode 100644
index 0000000000..768d595ed6
--- /dev/null
+++ b/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClient/PerfMapType.cs
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Microsoft.Diagnostics.NETCore.Client
+{
+ public enum PerfMapType
+ {
+ None = 0,
+ All = 1,
+ JitDump = 2,
+ PerfMap = 3
+ }
+}
diff --git a/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/IpcCommands.cs b/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/IpcCommands.cs
index da251b7750..f9eb3019ef 100644
--- a/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/IpcCommands.cs
+++ b/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/IpcCommands.cs
@@ -46,6 +46,10 @@ internal enum ProcessCommandId : byte
ResumeRuntime = 0x01,
GetProcessEnvironment = 0x02,
SetEnvironmentVariable = 0x03,
- GetProcessInfo2 = 0x04
+ GetProcessInfo2 = 0x04,
+ EnablePerfMap = 0x05,
+ DisablePerfMap = 0x06,
+ ApplyStartupHook = 0x07,
+ GetProcessInfo3 = 0x08
}
}
diff --git a/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/ProcessInfo.cs b/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/ProcessInfo.cs
index 044065b149..4a5c75a61c 100644
--- a/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/ProcessInfo.cs
+++ b/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/ProcessInfo.cs
@@ -53,10 +53,28 @@ internal static ProcessInfo ParseV1(byte[] payload)
internal static ProcessInfo ParseV2(byte[] payload)
{
int index = 0;
- ProcessInfo processInfo = ParseCommon(payload, ref index);
+ return ParseCommon2(payload, ref index);
+ }
- processInfo.ManagedEntrypointAssemblyName = IpcHelpers.ReadString(payload, ref index);
- processInfo.ClrProductVersionString = IpcHelpers.ReadString(payload, ref index);
+ ///
+ /// Parses a ProcessInfo3 payload.
+ ///
+ internal static ProcessInfo ParseV3(byte[] payload)
+ {
+ int index = 0;
+
+ // The ProcessInfo3 command is intended to allow the addition of new fields in future versions so
+ // long as the version field is incremented; prior fields shall not be changed or removed.
+ // Read the version field, parse the common payload, and dynamically parse the remainder depending on the version.
+ uint version = BinaryPrimitives.ReadUInt32LittleEndian(new ReadOnlySpan(payload, index, 4));
+ index += sizeof(uint);
+
+ ProcessInfo processInfo = ParseCommon2(payload, ref index);
+
+ if (version >= 1)
+ {
+ processInfo.PortableRuntimeIdentifier = IpcHelpers.ReadString(payload, ref index);
+ }
return processInfo;
}
@@ -80,6 +98,44 @@ private static ProcessInfo ParseCommon(byte[] payload, ref int index)
return processInfo;
}
+ internal bool TryGetProcessClrVersion(out Version version)
+ {
+ version = null;
+ if (string.IsNullOrEmpty(ClrProductVersionString))
+ {
+ return false;
+ }
+
+ // The version is of the SemVer2 form: ..[-][+]
+ // Remove the prerelease and metadata version information before parsing.
+
+ ReadOnlySpan versionSpan = ClrProductVersionString.AsSpan();
+ int metadataIndex = versionSpan.IndexOf('+');
+ if (-1 == metadataIndex)
+ {
+ metadataIndex = versionSpan.Length;
+ }
+
+ ReadOnlySpan noMetadataVersion = versionSpan.Slice(0, metadataIndex);
+ int prereleaseIndex = noMetadataVersion.IndexOf('-');
+ if (-1 == prereleaseIndex)
+ {
+ prereleaseIndex = metadataIndex;
+ }
+
+ return Version.TryParse(noMetadataVersion.Slice(0, prereleaseIndex).ToString(), out version);
+ }
+
+ private static ProcessInfo ParseCommon2(byte[] payload, ref int index)
+ {
+ ProcessInfo processInfo = ParseCommon(payload, ref index);
+
+ processInfo.ManagedEntrypointAssemblyName = IpcHelpers.ReadString(payload, ref index);
+ processInfo.ClrProductVersionString = IpcHelpers.ReadString(payload, ref index);
+
+ return processInfo;
+ }
+
public ulong ProcessId { get; private set; }
public Guid RuntimeInstanceCookie { get; private set; }
public string CommandLine { get; private set; }
@@ -87,5 +143,6 @@ private static ProcessInfo ParseCommon(byte[] payload, ref int index)
public string ProcessArchitecture { get; private set; }
public string ManagedEntrypointAssemblyName { get; private set; }
public string ClrProductVersionString { get; private set; }
+ public string PortableRuntimeIdentifier { get; private set; }
}
}
diff --git a/src/SOS/SOS.UnitTests/Scripts/GCPOH.script b/src/SOS/SOS.UnitTests/Scripts/GCPOH.script
index 2c223a6bf0..bcb855c79e 100644
--- a/src/SOS/SOS.UnitTests/Scripts/GCPOH.script
+++ b/src/SOS/SOS.UnitTests/Scripts/GCPOH.script
@@ -52,6 +52,11 @@ VERIFY:\s*Statistics:\s+
VERIFY:\s+MT\s+Count\s+TotalSize\s+Class\s+Name\s+
VERIFY:\s+\s+\s+\s+System.Byte\[\]\s+
+SOSCOMMAND:DumpHeap -stat -gen poh
+VERIFY:\s*Statistics:\s+
+VERIFY:\s+MT\s+Count\s+TotalSize\s+Class\s+Name\s+
+VERIFY:\s+\s+\s+\s+System.Byte\[\]\s+
+
SOSCOMMAND:EEHeap
VERIFY:\s*Loader Heap:\s+
VERIFY:\s+System Domain:\s+\s+
diff --git a/src/SOS/SOS.UnitTests/Scripts/GCTests.script b/src/SOS/SOS.UnitTests/Scripts/GCTests.script
index 38be904a97..671e4e2e15 100644
--- a/src/SOS/SOS.UnitTests/Scripts/GCTests.script
+++ b/src/SOS/SOS.UnitTests/Scripts/GCTests.script
@@ -82,6 +82,16 @@ VERIFY:\s*Statistics:\s+
VERIFY:\s+MT\s+Count\s+TotalSize\s+Class\s+Name\s+
VERIFY:\s+\s+\s+\s+GCWhere\s+
+SOSCOMMAND:DumpHeap -stat -gen gen0
+VERIFY:\s*Statistics:\s+
+VERIFY:\s+MT\s+Count\s+TotalSize\s+Class\s+Name\s+
+VERIFY:\s+\s+\s+\s+GCWhere\s+
+
+IFDEF:WINDOWS
+SOSCOMMAND:DumpHeap -stat -gen xxx
+VERIFY:\s*System\.ArgumentException: Unknown generation: xxx\. Only gen0, gen1, gen2, loh \(large\), poh \(pinned\) and foh \(frozen\) are supported\s+
+ENDIF:WINDOWS
+
IFDEF:WINDOWS
SOSCOMMAND:DumpHeap -strings
VERIFY:\s+\s+\s+\s+
diff --git a/src/SOS/Strike/gchist.cpp b/src/SOS/Strike/gchist.cpp
index 4885b83776..f656cb1183 100644
--- a/src/SOS/Strike/gchist.cpp
+++ b/src/SOS/Strike/gchist.cpp
@@ -2,9 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// ==++==
-//
-
-//
+//
+
+//
// ==--==
/****************************************************************************
* STRIKE.C *
@@ -33,8 +33,8 @@
#include
#include "strike.h"
-// We need to define the target address type. This will be used in the
-// functions that read directly from the debuggee address space, vs. using
+// We need to define the target address type. This will be used in the
+// functions that read directly from the debuggee address space, vs. using
// the DAC tgo read the DAC-ized data structures.
#include "daccess.h"
@@ -70,7 +70,7 @@
struct PlugRecord
{
PlugRecord *next;
-
+
size_t PlugStart;
size_t PlugEnd;
size_t Delta;
@@ -81,7 +81,7 @@ struct PlugRecord
struct PromoteRecord
{
PromoteRecord *next;
-
+
size_t Root;
size_t Value;
size_t methodTable;
@@ -92,7 +92,7 @@ struct PromoteRecord
struct RelocRecord
{
RelocRecord *next;
-
+
size_t Root;
size_t PrevValue;
size_t NewValue;
@@ -104,14 +104,14 @@ struct RelocRecord
struct GCRecord
{
ULONG64 GCCount;
-
+
// BOOL IsComplete() { return bFinished && bHaveStart; }
-
+
PlugRecord *PlugList;
RelocRecord *RelocList;
PromoteRecord *PromoteList;
- void AddPlug(PlugRecord& p) {
+ void AddPlug(PlugRecord& p) {
PlugRecord *pTmp = PlugList;
PlugList = new PlugRecord(p);
PlugList->next = pTmp;
@@ -158,7 +158,7 @@ struct GCRecord
}
return ret;
}
-
+
void Clear() {
PlugRecord *pTrav = PlugList;
@@ -183,8 +183,8 @@ struct GCRecord
}
ZeroMemory(this,sizeof(GCRecord));
- }
-
+ }
+
};
#define MAX_GCRECORDS 500
@@ -197,7 +197,7 @@ void GcHistClear()
{
g_records[i].Clear();
}
- g_recordCount = 0;
+ g_recordCount = 0;
}
void GcHistAddLog(LPCSTR msg, StressMsg* stressMsg)
@@ -206,12 +206,12 @@ void GcHistAddLog(LPCSTR msg, StressMsg* stressMsg)
{
return;
}
-
+
if (strcmp(msg, ThreadStressLog::gcPlugMoveMsg()) == 0)
{
PlugRecord pr;
// this is a plug message
- _ASSERTE(stressMsg->numberOfArgs == 3);
+ _ASSERTE(stressMsg->GetNumberOfArgs() == 3);
pr.PlugStart = (size_t) stressMsg->args[0];
pr.PlugEnd = (size_t) stressMsg->args[1];
pr.Delta = (size_t) stressMsg->args[2];
@@ -221,18 +221,18 @@ void GcHistAddLog(LPCSTR msg, StressMsg* stressMsg)
else if (strcmp(msg, ThreadStressLog::gcRootMsg()) == 0)
{
// this is a root message
- _ASSERTE(stressMsg->numberOfArgs == 4);
+ _ASSERTE(stressMsg->GetNumberOfArgs() == 4);
RelocRecord rr;
rr.Root = (size_t) stressMsg->args[0];
rr.PrevValue = (size_t) stressMsg->args[1];
rr.NewValue = (size_t) stressMsg->args[2];
rr.methodTable = (size_t) stressMsg->args[3];
- g_records[g_recordCount].AddReloc(rr);
+ g_records[g_recordCount].AddReloc(rr);
}
else if (strcmp(msg, ThreadStressLog::gcRootPromoteMsg()) == 0)
{
// this is a promote message
- _ASSERTE(stressMsg->numberOfArgs == 3);
+ _ASSERTE(stressMsg->GetNumberOfArgs() == 3);
PromoteRecord pr;
pr.Root = (size_t) stressMsg->args[0];
pr.Value = (size_t) stressMsg->args[1];
@@ -242,7 +242,7 @@ void GcHistAddLog(LPCSTR msg, StressMsg* stressMsg)
else if (strcmp(msg, ThreadStressLog::gcStartMsg()) == 0)
{
// Gc start!
- _ASSERTE(stressMsg->numberOfArgs == 3);
+ _ASSERTE(stressMsg->GetNumberOfArgs() == 3);
ULONG64 gc_count = (ULONG64) stressMsg->args[0];
g_records[g_recordCount].GCCount = gc_count;
g_recordCount++;
@@ -258,11 +258,11 @@ void GcHistAddLog(LPCSTR msg, StressMsg* stressMsg)
DECLARE_API(HistStats)
{
INIT_API();
-
+
ExtOut ("%8s %8s %8s\n",
"GCCount", "Promotes", "Relocs");
ExtOut ("-----------------------------------\n");
-
+
// Just traverse the data structure, printing basic stats
for (UINT i=0; i < g_recordCount; i++)
{
@@ -277,15 +277,15 @@ DECLARE_API(HistStats)
}
BOOL bErrorFound = FALSE;
-
+
// Check for duplicate Reloc or Promote messages within one gc.
// Method is very inefficient, improve it later.
for (UINT i=0; i < g_recordCount; i++)
- {
+ {
{ // Promotes
PromoteRecord *Iter = g_records[i].PromoteList;
UINT GCCount = (UINT) g_records[i].GCCount;
- while (Iter)
+ while (Iter)
{
PromoteRecord *innerIter = Iter->next;
while (innerIter)
@@ -299,15 +299,15 @@ DECLARE_API(HistStats)
}
innerIter = innerIter->next;
}
-
- Iter = Iter->next;
+
+ Iter = Iter->next;
}
}
{ // Relocates
RelocRecord *Iter = g_records[i].RelocList;
UINT GCCount = (UINT) g_records[i].GCCount;
- while (Iter)
+ while (Iter)
{
RelocRecord *innerIter = Iter->next;
while (innerIter)
@@ -321,17 +321,17 @@ DECLARE_API(HistStats)
}
innerIter = innerIter->next;
}
-
- Iter = Iter->next;
+
+ Iter = Iter->next;
}
- }
+ }
}
if (!bErrorFound)
{
ExtOut ("No duplicate promote or relocate messages found in the log.\n");
}
-
+
return Status;
}
@@ -341,7 +341,7 @@ DECLARE_API(HistRoot)
size_t nArg;
StringHolder rootstr;
- CMDValue arg[] =
+ CMDValue arg[] =
{
// vptr, type
{&rootstr.data, COSTRING},
@@ -357,13 +357,13 @@ DECLARE_API(HistRoot)
}
size_t Root = (size_t) GetExpression(rootstr.data);
-
+
ExtOut ("%8s %" POINTERSIZE "s %" POINTERSIZE "s %9s %20s\n",
"GCCount", "Value", "MT", "Promoted?", "Notes");
ExtOut ("---------------------------------------------------------\n");
bool bBoringPeople = false;
-
+
// Just traverse the data structure, printing basic stats
for (UINT i=0; i < g_recordCount; i++)
{
@@ -412,7 +412,7 @@ DECLARE_API(HistRoot)
if (pRelocRec != NULL)
{
bBoringPeople = false;
-
+
ExtOut ("%8d %p %p %9s ", GCCount,
SOS_PTR(pRelocRec->NewValue),
SOS_PTR(pRelocRec->methodTable),
@@ -445,8 +445,8 @@ DECLARE_API(HistRoot)
ExtOut ("...\n");
bBoringPeople = true;
}
- }
- }
+ }
+ }
return Status;
}
@@ -456,7 +456,7 @@ DECLARE_API(HistObjFind)
size_t nArg;
StringHolder objstr;
- CMDValue arg[] =
+ CMDValue arg[] =
{
// vptr, type
{&objstr.data, COSTRING},
@@ -472,14 +472,14 @@ DECLARE_API(HistObjFind)
}
size_t object = (size_t) GetExpression(objstr.data);
-
+
ExtOut ("%8s %" POINTERSIZE "s %40s\n",
"GCCount", "Object", "Message");
ExtOut ("---------------------------------------------------------\n");
size_t curAddress = object;
bool bBoringPeople = false;
-
+
// Just traverse the data structure, printing basic stats
for (UINT i=0; i < g_recordCount; i++)
{
@@ -487,8 +487,8 @@ DECLARE_API(HistObjFind)
{
break;
}
-
- UINT GCCount = (UINT) g_records[i].GCCount;
+
+ UINT GCCount = (UINT) g_records[i].GCCount;
PromoteRecord *pPtr = g_records[i].PromoteList;
while(pPtr)
@@ -518,14 +518,14 @@ DECLARE_API(HistObjFind)
}
pReloc = pReloc->next;
}
-
+
if (!bBoringPeople)
{
ExtOut ("...\n");
bBoringPeople = true;
}
- }
+ }
return Status;
}
@@ -535,7 +535,7 @@ DECLARE_API(HistObj)
size_t nArg;
StringHolder objstr;
- CMDValue arg[] =
+ CMDValue arg[] =
{
// vptr, type
{&objstr.data, COSTRING},
@@ -551,13 +551,13 @@ DECLARE_API(HistObj)
}
size_t object = (size_t) GetExpression(objstr.data);
-
+
ExtOut ("%8s %" POINTERSIZE "s %40s\n",
"GCCount", "Object", "Roots");
ExtOut ("---------------------------------------------------------\n");
size_t curAddress = object;
-
+
// Just traverse the data structure, printing basic stats
for (UINT i=0; i < g_recordCount; i++)
{
@@ -565,7 +565,7 @@ DECLARE_API(HistObj)
{
break;
}
-
+
UINT GCCount = (UINT) g_records[i].GCCount;
ExtOut ("%8d %p ", GCCount, SOS_PTR(curAddress));
@@ -592,8 +592,8 @@ DECLARE_API(HistObj)
}
ExtOut ("\n");
- curAddress = candidateCurAddress;
- }
+ curAddress = candidateCurAddress;
+ }
return Status;
}
@@ -608,10 +608,10 @@ DECLARE_API(HistInit)
{
ExtOut("Unable to find stress log via DAC\n");
return E_FAIL;
- }
-
+ }
+
ExtOut ("Attempting to read Stress log\n");
-
+
Status = StressLog::Dump(stressLogAddr, NULL, g_ExtData);
if (Status == S_OK)
ExtOut("SUCCESS: GCHist structures initialized\n");
diff --git a/src/SOS/Strike/stressLogDump.cpp b/src/SOS/Strike/stressLogDump.cpp
index 801a2344cb..3b851555d8 100644
--- a/src/SOS/Strike/stressLogDump.cpp
+++ b/src/SOS/Strike/stressLogDump.cpp
@@ -2,14 +2,14 @@
// The .NET Foundation licenses this file to you under the MIT license.
// ==++==
-//
-
-//
+//
+
+//
// ==--==
#include "strike.h"
#include "util.h"
-#include
+#include
#include
#ifndef STRESS_LOG
@@ -24,11 +24,11 @@ void GcHistAddLog(LPCSTR msg, StressMsg* stressMsg);
/*********************************************************************************/
-static const WCHAR* getTime(const FILETIME* time, __out_ecount (buffLen) WCHAR* buff, int buffLen)
+static const WCHAR* getTime(const FILETIME* time, __out_ecount (buffLen) WCHAR* buff, int buffLen)
{
SYSTEMTIME systemTime;
static const WCHAR badTime[] = W("BAD TIME");
-
+
if (!FileTimeToSystemTime(time, &systemTime))
return badTime;
@@ -47,24 +47,24 @@ static const WCHAR* getTime(const FILETIME* time, __out_ecount (buffLen) WCHAR*
if (ret == 0)
return badTime;
#endif // FEATURE_PAL else
-
+
return buff;
}
/*********************************************************************************/
-static inline __int64& toInt64(FILETIME& t)
+static inline __int64& toInt64(FILETIME& t)
{
return *((__int64 *) &t);
}
/*********************************************************************************/
-ThreadStressLog* ThreadStressLog::FindLatestThreadLog() const
+ThreadStressLog* ThreadStressLog::FindLatestThreadLog() const
{
const ThreadStressLog* latestLog = 0;
- for (const ThreadStressLog* ptr = this; ptr != NULL; ptr = ptr->next)
+ for (const ThreadStressLog* ptr = this; ptr != NULL; ptr = ptr->next)
{
if (ptr->readPtr != NULL)
- if (latestLog == 0 || ptr->readPtr->timeStamp > latestLog->readPtr->timeStamp)
+ if (latestLog == 0 || ptr->readPtr->GetTimeStamp() > latestLog->readPtr->GetTimeStamp())
latestLog = ptr;
}
return const_cast(latestLog);
@@ -84,7 +84,7 @@ const char *getFacilityName(DWORD_PTR lf)
{
return "`ALL`";
}
- else
+ else
{
buff[1] = '\0';
for ( int i = 0; i < 32; ++i )
@@ -117,11 +117,11 @@ void formatOutput(struct IDebugDataSpaces* memCallBack, ___in FILE* file, __inou
const SIZE_T capacity_buff = 2048;
LPWSTR buff = (LPWSTR)alloca(capacity_buff * sizeof(WCHAR));
static char formatCopy[256];
-
+
int iArgCount = 0;
-
+
strcpy_s(formatCopy, ARRAY_SIZE(formatCopy), format);
- for(;;)
+ for(;;)
{
char c = *ptr++;
if (c == 0)
@@ -130,24 +130,24 @@ void formatOutput(struct IDebugDataSpaces* memCallBack, ___in FILE* file, __inou
ptr[-1] = '}';
else if (c == '}')
ptr[-1] = '{';
- else if (c == '%')
+ else if (c == '%')
{
argsPtr++; // This format will consume one of the args
- if (*ptr == '%')
+ if (*ptr == '%')
{
ptr++; // skip the whole %%
- --argsPtr; // except for a %%
+ --argsPtr; // except for a %%
}
- else if (*ptr == 'p')
+ else if (*ptr == 'p')
{ // It is a %p
ptr++;
- if (isalpha(*ptr))
+ if (isalpha(*ptr))
{ // It is a special %p formatter
// Print the string up to that point
c = *ptr;
*ptr = 0; // Terminate the string temporarily
fprintf(file, format, args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
- *ptr = c; // Put it back
+ *ptr = c; // Put it back
// move the argument pointers past the part the was printed
format = ptr + 1;
@@ -155,7 +155,7 @@ void formatOutput(struct IDebugDataSpaces* memCallBack, ___in FILE* file, __inou
iArgCount = -1;
DWORD_PTR arg = DWORD_PTR(argsPtr[-1]);
- switch (c)
+ switch (c)
{
case 'M': // format as a method Desc
if (g_bDacBroken)
@@ -164,12 +164,12 @@ void formatOutput(struct IDebugDataSpaces* memCallBack, ___in FILE* file, __inou
}
else
{
- if (!IsMethodDesc(arg))
+ if (!IsMethodDesc(arg))
{
- if (arg != 0)
+ if (arg != 0)
fprintf(file, " (BAD Method)");
}
- else
+ else
{
DacpMethodDescData MethodDescData;
MethodDescData.Request(g_sos,(CLRDATA_ADDRESS)arg);
@@ -194,16 +194,16 @@ void formatOutput(struct IDebugDataSpaces* memCallBack, ___in FILE* file, __inou
}
else
{
- if (arg & 3)
+ if (arg & 3)
{
- arg &= ~3; // GC steals the lower bits for its own use during GC.
+ arg &= ~3; // GC steals the lower bits for its own use during GC.
fprintf(file, " Low Bit(s) Set");
}
if (!IsMethodTable(arg))
{
fprintf(file, " (BAD MethodTable)");
}
- else
+ else
{
NameForMT_s (arg, g_mdName, mdNameLen);
fprintf(file, " (%S)", g_mdName);
@@ -211,14 +211,14 @@ void formatOutput(struct IDebugDataSpaces* memCallBack, ___in FILE* file, __inou
}
break;
- case 'V':
- { // format as a C vtable pointer
+ case 'V':
+ { // format as a C vtable pointer
char Symbol[1024];
ULONG64 Displacement;
HRESULT hr = g_ExtSymbols->GetNameByOffset(TO_CDADDR(arg), Symbol, 1024, NULL, &Displacement);
- if (SUCCEEDED(hr) && Symbol[0] != '\0' && Displacement == 0)
+ if (SUCCEEDED(hr) && Symbol[0] != '\0' && Displacement == 0)
fprintf(file, " (%s)", Symbol);
- else
+ else
fprintf(file, " (Unknown VTable)");
}
break;
@@ -227,7 +227,7 @@ void formatOutput(struct IDebugDataSpaces* memCallBack, ___in FILE* file, __inou
char Symbol[1024];
ULONG64 Displacement;
HRESULT hr = g_ExtSymbols->GetNameByOffset (TO_CDADDR(arg), Symbol, 1024, NULL, &Displacement);
- if (SUCCEEDED (hr) && Symbol[0] != '\0')
+ if (SUCCEEDED (hr) && Symbol[0] != '\0')
{
fprintf (file, " (%s", Symbol);
if (Displacement)
@@ -236,16 +236,16 @@ void formatOutput(struct IDebugDataSpaces* memCallBack, ___in FILE* file, __inou
}
fprintf (file, ")");
}
- else
- fprintf (file, " (Unknown function)");
+ else
+ fprintf (file, " (Unknown function)");
}
break;
default:
- format = ptr; // Just print the character.
+ format = ptr; // Just print the character.
}
}
}
- else if (*ptr == 's' || (*ptr == 'h' && *(ptr+1) == 's' && ++ptr))
+ else if (*ptr == 's' || (*ptr == 'h' && *(ptr+1) == 's' && ++ptr))
{
HRESULT hr;
@@ -253,16 +253,16 @@ void formatOutput(struct IDebugDataSpaces* memCallBack, ___in FILE* file, __inou
// since we may have more than one %s in the format
ULONG cbStrBuf = 256;
char* strBuf = (char *)_alloca(cbStrBuf);
-
+
hr = memCallBack->ReadVirtual(TO_CDADDR((char* )args[iArgCount]), strBuf, cbStrBuf, 0);
- if (hr != S_OK)
+ if (hr != S_OK)
{
- strcpy_s(strBuf, cbStrBuf, "(#Could not read address of string#)");
+ strcpy_s(strBuf, cbStrBuf, "(#Could not read address of string#)");
}
- args[iArgCount] = strBuf;
+ args[iArgCount] = strBuf;
}
- else if (*ptr == 'S' || (*ptr == 'l' && *(ptr+1) == 's' && ++ptr))
+ else if (*ptr == 'S' || (*ptr == 'l' && *(ptr+1) == 's' && ++ptr))
{
HRESULT hr;
@@ -270,7 +270,7 @@ void formatOutput(struct IDebugDataSpaces* memCallBack, ___in FILE* file, __inou
// since we may have more than one %s in the format
ULONG cbWstrBuf = 256 * sizeof(WCHAR);
WCHAR* wstrBuf = (WCHAR *)_alloca(cbWstrBuf);
-
+
hr = memCallBack->ReadVirtual(TO_CDADDR((char* )args[iArgCount]), wstrBuf, cbWstrBuf, 0);
if (hr != S_OK)
{
@@ -291,7 +291,7 @@ void __cdecl
vDoOut(BOOL bToConsole, FILE* file, PCSTR Format, ...)
{
va_list Args;
-
+
va_start(Args, Format);
if (bToConsole)
@@ -306,7 +306,7 @@ vDoOut(BOOL bToConsole, FILE* file, PCSTR Format, ...)
va_end(Args);
}
-static TADDR GetFormatAddr(StressLog& inProcLog, uint32_t formatOffset, BOOL bHasModuleTable)
+static TADDR GetFormatAddr(StressLog& inProcLog, uint64_t formatOffset, BOOL bHasModuleTable)
{
// do we have a module table, and does it look valid?
if (bHasModuleTable && inProcLog.moduleOffset == (size_t)inProcLog.modules[0].baseAddress &&
@@ -318,34 +318,64 @@ static TADDR GetFormatAddr(StressLog& inProcLog, uint32_t formatOffset, BOOL bHa
{
if (inProcLog.modules[moduleIndex].baseAddress == nullptr)
break;
- size_t relativeOffset = formatOffset - moduleOffset;
+ uint64_t relativeOffset = formatOffset - moduleOffset;
if (relativeOffset < inProcLog.modules[moduleIndex].size)
{
- return relativeOffset + TO_TADDR(inProcLog.modules[moduleIndex].baseAddress);
+ return ((size_t)relativeOffset) + TO_TADDR(inProcLog.modules[moduleIndex].baseAddress);
}
moduleOffset += inProcLog.modules[moduleIndex].size;
}
}
// not found or invalid module table
// just assume it's an old style stress log
- return formatOffset + TO_TADDR(inProcLog.moduleOffset);
+ return ((size_t)formatOffset) + TO_TADDR(inProcLog.moduleOffset);
+}
+
+
+StressMsg* GetStressMsgInLatestVersion(StressMsg* rawMsg, int version)
+{
+ if (version >= 4)
+ {
+ return rawMsg;
+ }
+
+ struct StressMsgV3
+ {
+ uint32_t numberOfArgsLow : 3; // at most 7 arguments here
+ uint32_t formatOffset : 26; // low bits offset of format string in modules
+ uint32_t numberOfArgsHigh : 3; // extend number of args in a backward compat way
+ uint32_t facility; // facility used to log the entry
+ uint64_t timeStamp; // time when mssg was logged
+ };
+ static_assert(sizeof(StressMsg) == sizeof(StressMsgV3), "StressMsgV3 should be the same size as the current StressMsg struct");
+
+ StressMsgV3* msgV3 = reinterpret_cast(rawMsg);
+ uint32_t numberOfArgs = msgV3->numberOfArgsLow | (msgV3->numberOfArgsHigh << 3);
+ uint64_t formatOffset = msgV3->formatOffset;
+ uint32_t facility = msgV3->facility;
+ uint64_t timeStamp = msgV3->timeStamp;
+ rawMsg->SetNumberOfArgs(numberOfArgs);
+ rawMsg->SetFormatOffset(formatOffset);
+ rawMsg->SetFacility(facility);
+ rawMsg->SetTimeStamp(timeStamp);
+ return rawMsg;
}
/*********************************************************************************/
-HRESULT StressLog::Dump(ULONG64 outProcLog, const char* fileName, struct IDebugDataSpaces* memCallBack)
+HRESULT StressLog::Dump(ULONG64 outProcLog, const char* fileName, struct IDebugDataSpaces* memCallBack)
{
ULONG64 g_hThisInst;
BOOL bDoGcHist = (fileName == NULL);
FILE* file = NULL;
- // Fetch the circular buffer bookkeeping data
+ // Fetch the circular buffer bookkeeping data
StressLog inProcLog;
HRESULT hr = memCallBack->ReadVirtual(UL64_TO_CDA(outProcLog), &inProcLog, sizeof(StressLog), 0);
- if (hr != S_OK)
+ if (hr != S_OK)
{
return hr;
}
- if (inProcLog.logs.Load() == NULL || inProcLog.moduleOffset == 0)
+ if (inProcLog.logs.Load() == NULL || inProcLog.moduleOffset == 0)
{
ExtOut ( "----- No thread logs in the image: The stress log was probably not initialized correctly. -----\n");
return S_FALSE;
@@ -402,7 +432,7 @@ HRESULT StressLog::Dump(ULONG64 outProcLog, const char* fileName, struct IDebugD
// if this is the first time through, inProcPtr->chunkListHead may still contain
// the out-of-process value for the chunk pointer. NULL it to avoid AVs
if (TO_CDADDR(inProcPtr->chunkListHead) == outProcListHead)
- inProcPtr->chunkListHead = NULL;
+ inProcPtr->chunkListHead = NULL;
delete inProcPtr;
goto FREE_MEM;
}
@@ -413,7 +443,7 @@ HRESULT StressLog::Dump(ULONG64 outProcLog, const char* fileName, struct IDebugD
inProcPtr->curWriteChunk = inProcChunkPtr;
curPtrInitialized = TRUE;
}
-
+
outProcChunkPtr = TO_CDADDR(inProcChunkPtr->next);
*chunksPtr = inProcChunkPtr;
chunksPtr = &inProcChunkPtr->next;
@@ -425,9 +455,9 @@ HRESULT StressLog::Dump(ULONG64 outProcLog, const char* fileName, struct IDebugD
inProcChunkPtr->next = inProcPtr->chunkListHead;
inProcPtr->chunkListHead->prev = inProcChunkPtr;
inProcPtr->chunkListTail = inProcChunkPtr;
- }
+ }
} while (outProcChunkPtr != outProcListHead);
-
+
if (!curPtrInitialized)
{
delete inProcPtr;
@@ -436,9 +466,9 @@ HRESULT StressLog::Dump(ULONG64 outProcLog, const char* fileName, struct IDebugD
// TODO: fix on 64 bit
inProcPtr->Activate ();
- if (inProcPtr->readPtr->timeStamp > lastTimeStamp)
+ if (inProcPtr->readPtr->GetTimeStamp() > lastTimeStamp)
{
- lastTimeStamp = inProcPtr->readPtr->timeStamp;
+ lastTimeStamp = inProcPtr->readPtr->GetTimeStamp();
}
outProcPtr = TO_CDADDR(inProcPtr->next);
@@ -495,33 +525,33 @@ HRESULT StressLog::Dump(ULONG64 outProcLog, const char* fileName, struct IDebugD
{
ThreadStressLog* latestLog = logs->FindLatestThreadLog();
- if (IsInterrupt())
+ if (IsInterrupt())
{
vDoOut(bDoGcHist, file, "----- Interrupted by user -----\n");
break;
}
- if (latestLog == 0)
+ if (latestLog == 0)
{
break;
}
- StressMsg* latestMsg = latestLog->readPtr;
- if (latestMsg->formatOffset != 0 && !latestLog->CompletedDump())
+ StressMsg* latestMsg = GetStressMsgInLatestVersion(latestLog->readPtr, version);
+ if (latestMsg->GetFormatOffset() != 0 && !latestLog->CompletedDump())
{
- TADDR taFmt = GetFormatAddr(inProcLog, latestMsg->formatOffset, bHasModuleTable);
+ TADDR taFmt = GetFormatAddr(inProcLog, latestMsg->GetFormatOffset(), bHasModuleTable);
hr = memCallBack->ReadVirtual(TO_CDADDR(taFmt), format, 256, 0);
- if (hr != S_OK)
+ if (hr != S_OK)
strcpy_s(format, ARRAY_SIZE(format), "Could not read address of format string");
- double deltaTime = ((double) (latestMsg->timeStamp - inProcLog.startTimeStamp)) / inProcLog.tickFrequency;
+ double deltaTime = ((double) (latestMsg->GetTimeStamp() - inProcLog.startTimeStamp)) / inProcLog.tickFrequency;
if (bDoGcHist)
{
if (strcmp(format, ThreadStressLog::TaskSwitchMsg()) == 0)
{
latestLog->threadId = (unsigned)(size_t)latestMsg->args[0];
}
- GcHistAddLog(format, latestMsg);
+ GcHistAddLog(format, latestMsg);
}
else
{
@@ -530,16 +560,16 @@ HRESULT StressLog::Dump(ULONG64 outProcLog, const char* fileName, struct IDebugD
fprintf (file, "Task was switched from %x\n", (unsigned)(size_t)latestMsg->args[0]);
latestLog->threadId = (unsigned)(size_t)latestMsg->args[0];
}
- else
+ else
{
args = latestMsg->args;
- formatOutput(memCallBack, file, format, (unsigned)latestLog->threadId, deltaTime, latestMsg->facility, args);
+ formatOutput(memCallBack, file, format, (unsigned)latestLog->threadId, deltaTime, latestMsg->GetFacility(), args);
}
}
msgCtr++;
}
- latestLog->readPtr = latestLog->AdvanceRead();
+ latestLog->readPtr = latestLog->AdvanceRead(latestMsg->GetNumberOfArgs());
if (latestLog->CompletedDump())
{
latestLog->readPtr = NULL;
@@ -549,11 +579,11 @@ HRESULT StressLog::Dump(ULONG64 outProcLog, const char* fileName, struct IDebugD
}
}
- if (msgCtr % 64 == 0)
+ if (msgCtr % 64 == 0)
{
ExtOut("."); // to indicate progress
- if (msgCtr % (64*64) == 0)
- ExtOut("\n");
+ if (msgCtr % (64*64) == 0)
+ ExtOut("\n");
}
}
ExtOut("\n");
diff --git a/src/Tools/dotnet-counters/CounterMonitor.cs b/src/Tools/dotnet-counters/CounterMonitor.cs
index a017074386..5ec240d052 100644
--- a/src/Tools/dotnet-counters/CounterMonitor.cs
+++ b/src/Tools/dotnet-counters/CounterMonitor.cs
@@ -14,6 +14,7 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.Diagnostics.Monitoring.EventPipe;
using Microsoft.Diagnostics.NETCore.Client;
using Microsoft.Diagnostics.Tools.Counters.Exporters;
using Microsoft.Diagnostics.Tracing;
@@ -24,7 +25,10 @@ namespace Microsoft.Diagnostics.Tools.Counters
public class CounterMonitor
{
private const int BufferDelaySecs = 1;
+ private const string SharedSessionId = "SHARED"; // This should be identical to the one used by dotnet-monitor in MetricSourceConfiguration.cs
+ private static HashSet inactiveSharedSessions = new(StringComparer.OrdinalIgnoreCase);
+ private string _sessionId;
private int _processId;
private int _interval;
private CounterSet _counterList;
@@ -37,7 +41,7 @@ public class CounterMonitor
private bool _resumeRuntime;
private DiagnosticsClient _diagnosticsClient;
private EventPipeSession _session;
- private readonly string _metricsEventSourceSessionId;
+ private readonly string _clientId;
private int _maxTimeSeries;
private int _maxHistograms;
private TimeSpan _duration;
@@ -53,7 +57,8 @@ private class ProviderEventState
public CounterMonitor()
{
_pauseCmdSet = false;
- _metricsEventSourceSessionId = Guid.NewGuid().ToString();
+ _clientId = Guid.NewGuid().ToString();
+
_shouldExit = new TaskCompletionSource();
}
@@ -70,7 +75,8 @@ private void DynamicAllMonitor(TraceEvent obj)
// There's a potential race here between the two tasks but not a huge deal if we miss by one event.
_renderer.ToggleStatus(_pauseCmdSet);
- if (obj.ProviderName == "System.Diagnostics.Metrics")
+ // If a session received a MultipleSessionsConfiguredIncorrectlyError, ignore future shared events
+ if (obj.ProviderName == "System.Diagnostics.Metrics" && !inactiveSharedSessions.Contains(_clientId))
{
if (obj.EventName == "BeginInstrumentReporting")
{
@@ -112,6 +118,10 @@ private void DynamicAllMonitor(TraceEvent obj)
{
HandleMultipleSessionsNotSupportedError(obj);
}
+ else if (obj.EventName == "MultipleSessionsConfiguredIncorrectlyError")
+ {
+ HandleMultipleSessionsConfiguredIncorrectlyError(obj);
+ }
}
else if (obj.EventName == "EventCounters")
{
@@ -142,7 +152,7 @@ private void HandleBeginInstrumentReporting(TraceEvent obj)
string sessionId = (string)obj.PayloadValue(0);
string meterName = (string)obj.PayloadValue(1);
// string instrumentName = (string)obj.PayloadValue(3);
- if (sessionId != _metricsEventSourceSessionId)
+ if (sessionId != _sessionId)
{
return;
}
@@ -158,7 +168,7 @@ private void HandleCounterRate(TraceEvent obj)
string unit = (string)obj.PayloadValue(4);
string tags = (string)obj.PayloadValue(5);
string rateText = (string)obj.PayloadValue(6);
- if (sessionId != _metricsEventSourceSessionId)
+ if (sessionId != _sessionId || !Filter(meterName, instrumentName))
{
return;
}
@@ -182,7 +192,7 @@ private void HandleGauge(TraceEvent obj)
string unit = (string)obj.PayloadValue(4);
string tags = (string)obj.PayloadValue(5);
string lastValueText = (string)obj.PayloadValue(6);
- if (sessionId != _metricsEventSourceSessionId)
+ if (sessionId != _sessionId || !Filter(meterName, instrumentName))
{
return;
}
@@ -217,7 +227,7 @@ private void HandleUpDownCounterValue(TraceEvent obj)
string tags = (string)obj.PayloadValue(5);
//string rateText = (string)obj.PayloadValue(6); // Not currently using rate for UpDownCounters.
string valueText = (string)obj.PayloadValue(7);
- if (sessionId != _metricsEventSourceSessionId)
+ if (sessionId != _sessionId || !Filter(meterName, instrumentName))
{
return;
}
@@ -247,7 +257,7 @@ private void HandleHistogram(TraceEvent obj)
string unit = (string)obj.PayloadValue(4);
string tags = (string)obj.PayloadValue(5);
string quantilesText = (string)obj.PayloadValue(6);
- if (sessionId != _metricsEventSourceSessionId)
+ if (sessionId != _sessionId || !Filter(meterName, instrumentName))
{
return;
}
@@ -263,7 +273,7 @@ private void HandleHistogram(TraceEvent obj)
private void HandleHistogramLimitReached(TraceEvent obj)
{
string sessionId = (string)obj.PayloadValue(0);
- if (sessionId != _metricsEventSourceSessionId)
+ if (sessionId != _clientId)
{
return;
}
@@ -276,7 +286,7 @@ private void HandleHistogramLimitReached(TraceEvent obj)
private void HandleTimeSeriesLimitReached(TraceEvent obj)
{
string sessionId = (string)obj.PayloadValue(0);
- if (sessionId != _metricsEventSourceSessionId)
+ if (sessionId != _sessionId)
{
return;
}
@@ -290,7 +300,7 @@ private void HandleError(TraceEvent obj)
{
string sessionId = (string)obj.PayloadValue(0);
string error = (string)obj.PayloadValue(1);
- if (sessionId != _metricsEventSourceSessionId)
+ if (sessionId != _sessionId)
{
return;
}
@@ -305,7 +315,7 @@ private void HandleObservableInstrumentCallbackError(TraceEvent obj)
{
string sessionId = (string)obj.PayloadValue(0);
string error = (string)obj.PayloadValue(1);
- if (sessionId != _metricsEventSourceSessionId)
+ if (sessionId != _sessionId)
{
return;
}
@@ -318,18 +328,28 @@ private void HandleObservableInstrumentCallbackError(TraceEvent obj)
private void HandleMultipleSessionsNotSupportedError(TraceEvent obj)
{
string runningSessionId = (string)obj.PayloadValue(0);
- if (runningSessionId == _metricsEventSourceSessionId)
+ if (runningSessionId == _sessionId)
{
// If our session is the one that is running then the error is not for us,
// it is for some other session that came later
return;
}
_renderer.SetErrorText(
- "Error: Another metrics collection session is already in progress for the target process, perhaps from another tool?" + Environment.NewLine +
+ "Error: Another metrics collection session is already in progress for the target process." + Environment.NewLine +
"Concurrent sessions are not supported.");
_shouldExit.TrySetResult((int)ReturnCode.SessionCreationError);
}
+ private void HandleMultipleSessionsConfiguredIncorrectlyError(TraceEvent obj)
+ {
+ if (TraceEventExtensions.TryCreateSharedSessionConfiguredIncorrectlyMessage(obj, _clientId, out string message))
+ {
+ _renderer.SetErrorText(message);
+ inactiveSharedSessions.Add(_clientId);
+ _shouldExit.TrySetResult((int)ReturnCode.SessionCreationError);
+ }
+ }
+
private static KeyValuePair[] ParseQuantiles(string quantileList)
{
string[] quantileParts = quantileList.Split(';', StringSplitOptions.RemoveEmptyEntries);
@@ -840,21 +860,35 @@ private EventPipeProvider[] GetEventPipeProviders()
metrics.Append(string.Join(',', providerCounters));
}
}
+
+ // Shared Session Id was added in 8.0 - older runtimes will not properly support it.
+ _sessionId = Guid.NewGuid().ToString();
+ if (_diagnosticsClient.GetProcessInfo().TryGetProcessClrVersion(out Version version))
+ {
+ _sessionId = version.Major >= 8 ? SharedSessionId : _sessionId;
+ }
+
EventPipeProvider metricsEventSourceProvider =
new("System.Diagnostics.Metrics", EventLevel.Informational, TimeSeriesValues,
new Dictionary()
{
- { "SessionId", _metricsEventSourceSessionId },
+ { "SessionId", _sessionId },
{ "Metrics", metrics.ToString() },
{ "RefreshInterval", _interval.ToString() },
{ "MaxTimeSeries", _maxTimeSeries.ToString() },
- { "MaxHistograms", _maxHistograms.ToString() }
+ { "MaxHistograms", _maxHistograms.ToString() },
+ { "ClientId", _clientId }
}
);
return eventCounterProviders.Append(metricsEventSourceProvider).ToArray();
}
+ private bool Filter(string meterName, string instrumentName)
+ {
+ return _counterList.GetCounters(meterName).Contains(instrumentName) || _counterList.IncludesAllCounters(meterName);
+ }
+
private Task Start()
{
EventPipeProvider[] providers = GetEventPipeProviders();
diff --git a/src/Tools/dotnet-counters/dotnet-counters.csproj b/src/Tools/dotnet-counters/dotnet-counters.csproj
index 777b8b9647..790b04b95d 100644
--- a/src/Tools/dotnet-counters/dotnet-counters.csproj
+++ b/src/Tools/dotnet-counters/dotnet-counters.csproj
@@ -1,4 +1,4 @@
-
+
net6.0
@@ -23,6 +23,7 @@
+
diff --git a/src/Tools/dotnet-counters/runtimeconfig.template.json b/src/Tools/dotnet-counters/runtimeconfig.template.json
index f022b7ffce..8c606df890 100644
--- a/src/Tools/dotnet-counters/runtimeconfig.template.json
+++ b/src/Tools/dotnet-counters/runtimeconfig.template.json
@@ -1,3 +1,3 @@
{
- "rollForwardOnNoCandidateFx": 2
-}
\ No newline at end of file
+ "rollForward": "major"
+}
diff --git a/src/Tools/dotnet-dsrouter/runtimeconfig.template.json b/src/Tools/dotnet-dsrouter/runtimeconfig.template.json
index f022b7ffce..8c606df890 100644
--- a/src/Tools/dotnet-dsrouter/runtimeconfig.template.json
+++ b/src/Tools/dotnet-dsrouter/runtimeconfig.template.json
@@ -1,3 +1,3 @@
{
- "rollForwardOnNoCandidateFx": 2
-}
\ No newline at end of file
+ "rollForward": "major"
+}
diff --git a/src/Tools/dotnet-dump/runtimeconfig.template.json b/src/Tools/dotnet-dump/runtimeconfig.template.json
index f022b7ffce..8c606df890 100644
--- a/src/Tools/dotnet-dump/runtimeconfig.template.json
+++ b/src/Tools/dotnet-dump/runtimeconfig.template.json
@@ -1,3 +1,3 @@
{
- "rollForwardOnNoCandidateFx": 2
-}
\ No newline at end of file
+ "rollForward": "major"
+}
diff --git a/src/Tools/dotnet-gcdump/runtimeconfig.template.json b/src/Tools/dotnet-gcdump/runtimeconfig.template.json
index f022b7ffce..8c606df890 100644
--- a/src/Tools/dotnet-gcdump/runtimeconfig.template.json
+++ b/src/Tools/dotnet-gcdump/runtimeconfig.template.json
@@ -1,3 +1,3 @@
{
- "rollForwardOnNoCandidateFx": 2
-}
\ No newline at end of file
+ "rollForward": "major"
+}
diff --git a/src/Tools/dotnet-sos/runtimeconfig.template.json b/src/Tools/dotnet-sos/runtimeconfig.template.json
index f022b7ffce..8c606df890 100644
--- a/src/Tools/dotnet-sos/runtimeconfig.template.json
+++ b/src/Tools/dotnet-sos/runtimeconfig.template.json
@@ -1,3 +1,3 @@
{
- "rollForwardOnNoCandidateFx": 2
-}
\ No newline at end of file
+ "rollForward": "major"
+}
diff --git a/src/Tools/dotnet-stack/runtimeconfig.template.json b/src/Tools/dotnet-stack/runtimeconfig.template.json
index f022b7ffce..8c606df890 100644
--- a/src/Tools/dotnet-stack/runtimeconfig.template.json
+++ b/src/Tools/dotnet-stack/runtimeconfig.template.json
@@ -1,3 +1,3 @@
{
- "rollForwardOnNoCandidateFx": 2
-}
\ No newline at end of file
+ "rollForward": "major"
+}
diff --git a/src/Tools/dotnet-trace/runtimeconfig.template.json b/src/Tools/dotnet-trace/runtimeconfig.template.json
index f022b7ffce..8c606df890 100644
--- a/src/Tools/dotnet-trace/runtimeconfig.template.json
+++ b/src/Tools/dotnet-trace/runtimeconfig.template.json
@@ -1,3 +1,3 @@
{
- "rollForwardOnNoCandidateFx": 2
-}
\ No newline at end of file
+ "rollForward": "major"
+}
diff --git a/src/dbgshim/dbgshim.cpp b/src/dbgshim/dbgshim.cpp
index 2b5411da32..becdea9266 100644
--- a/src/dbgshim/dbgshim.cpp
+++ b/src/dbgshim/dbgshim.cpp
@@ -159,7 +159,7 @@ typedef HRESULT (STDAPICALLTYPE *FPCoreCLRCreateCordbObject3)(
typedef HRESULT (STDAPICALLTYPE *FPCreateRemoteCordbObject)(
DWORD port,
- LPCSTR assemblyBasePath,
+ LPCWSTR assemblyBasePath,
IUnknown **ppCordb);
HRESULT CreateCoreDbg(
@@ -2157,7 +2157,7 @@ CLRCreateInstance(
return pDebuggingImpl->QueryInterface(riid, ppInterface);
}
-HRESULT CreateCoreDbgRemotePort(HMODULE hDBIModule, DWORD portId, LPCSTR assemblyBasePath, IUnknown **ppCordb)
+HRESULT CreateCoreDbgRemotePort(HMODULE hDBIModule, DWORD portId, LPCWSTR assemblyBasePath, IUnknown **ppCordb)
{
PUBLIC_CONTRACT;
HRESULT hr = S_OK;
@@ -2178,15 +2178,15 @@ DLLEXPORT
HRESULT
RegisterForRuntimeStartupRemotePort(
_In_ DWORD dwRemotePortId,
- _In_ LPCSTR mscordbiPath,
- _In_ LPCSTR assemblyBasePath,
+ _In_ LPCWSTR mscordbiPath,
+ _In_ LPCWSTR assemblyBasePath,
_Out_ IUnknown ** ppCordb)
{
PUBLIC_CONTRACT;
HRESULT hr = S_OK;
HMODULE hMod = NULL;
- hMod = LoadLibraryA(mscordbiPath);
+ hMod = LoadLibraryW(mscordbiPath);
if (hMod == NULL)
{
hr = CORDBG_E_DEBUG_COMPONENT_MISSING;
diff --git a/src/dbgshim/dbgshim.h b/src/dbgshim/dbgshim.h
index b186a5da8c..43b44ef5c1 100644
--- a/src/dbgshim/dbgshim.h
+++ b/src/dbgshim/dbgshim.h
@@ -109,6 +109,6 @@ CreateDebuggingInterfaceFromVersion3(
EXTERN_C HRESULT
RegisterForRuntimeStartupRemotePort(
_In_ DWORD dwRemotePortId,
- _In_ LPCSTR mscordbiPath,
- _In_ LPCSTR assemblyBasePath,
+ _In_ LPCWSTR mscordbiPath,
+ _In_ LPCWSTR assemblyBasePath,
_Out_ IUnknown ** ppCordb);
diff --git a/src/shared/inc/sospriv.idl b/src/shared/inc/sospriv.idl
index b1a3b18e06..a0a42fff89 100644
--- a/src/shared/inc/sospriv.idl
+++ b/src/shared/inc/sospriv.idl
@@ -415,7 +415,7 @@ interface ISOSDacInterface8 : IUnknown
// Increment anytime there is a change in the data structures that SOS depends on like
// stress log structs (StressMsg, StressLogChunck, ThreadStressLog, etc), exception
// stack traces (StackTraceElement), the PredefinedTlsSlots enums, etc.
-cpp_quote("#define SOS_BREAKING_CHANGE_VERSION 3")
+cpp_quote("#define SOS_BREAKING_CHANGE_VERSION 4")
[
object,
diff --git a/src/shared/inc/stresslog.h b/src/shared/inc/stresslog.h
index 1038716174..5068daef2d 100644
--- a/src/shared/inc/stresslog.h
+++ b/src/shared/inc/stresslog.h
@@ -537,28 +537,71 @@ inline BOOL StressLog::LogOn(unsigned facility, unsigned level)
// The order of fields is important. Keep the prefix length as the first field.
// And make sure the timeStamp field is naturally alligned, so we don't waste
// space on 32-bit platforms
-struct StressMsg {
- static const size_t formatOffsetBits = 26;
- union {
- struct {
- uint32_t numberOfArgs : 3; // at most 7 arguments here
- uint32_t formatOffset : formatOffsetBits; // offset of string in mscorwks
- uint32_t numberOfArgsX : 3; // extend number of args in a backward compat way
- };
- uint32_t fmtOffsCArgs; // for optimized access
- };
- uint32_t facility; // facility used to log the entry
- uint64_t timeStamp; // time when mssg was logged
- void* args[0]; // size given by numberOfArgs
+struct StressMsg
+{
+private:
+ static const size_t formatOffsetLowBits = 26;
+ static const size_t formatOffsetHighBits = 13;
+
+ // We split the format offset to ensure that we utilize every bit and that
+ // the compiler does not align the format offset to a new 64-bit boundary.
+ uint64_t facility: 32; // facility used to log the entry
+ uint64_t numberOfArgs : 6; // number of arguments
+ uint64_t formatOffsetLow: formatOffsetLowBits; // offset of format string in modules
+ uint64_t formatOffsetHigh: formatOffsetHighBits; // offset of format string in modules
+ uint64_t timeStamp: 51; // time when msg was logged (100ns ticks since runtime start)
+
+public:
+ void* args[0]; // size given by numberOfArgs
+
+ void SetFormatOffset(uint64_t offset)
+ {
+ formatOffsetLow = (uint32_t)(offset & ((1 << formatOffsetLowBits) - 1));
+ formatOffsetHigh = offset >> formatOffsetLowBits;
+ }
+
+ uint64_t GetFormatOffset()
+ {
+ return (formatOffsetHigh << formatOffsetLowBits) | formatOffsetLow;
+ }
+
+ void SetNumberOfArgs(uint32_t num)
+ {
+ numberOfArgs = num;
+ }
+
+ uint32_t GetNumberOfArgs()
+ {
+ return numberOfArgs;
+ }
+
+ void SetFacility(uint32_t fac)
+ {
+ facility = fac;
+ }
+
+ uint32_t GetFacility()
+ {
+ return facility;
+ }
+
+ uint64_t GetTimeStamp()
+ {
+ return timeStamp;
+ }
+
+ void SetTimeStamp(uint64_t time)
+ {
+ timeStamp = time;
+ }
static const size_t maxArgCnt = 63;
- static const size_t maxOffset = 1 << formatOffsetBits;
+ static const int64_t maxOffset = (int64_t)1 << (formatOffsetLowBits + formatOffsetHighBits);
static size_t maxMsgSize ()
{ return sizeof(StressMsg) + maxArgCnt*sizeof(void*); }
-
- friend class ThreadStressLog;
- friend class StressLog;
};
+
+static_assert(sizeof(StressMsg) == sizeof(uint64_t) * 2, "StressMsg bitfields aren't aligned correctly");
#ifdef HOST_64BIT
#define STRESSLOG_CHUNK_SIZE (32 * 1024)
#else //HOST_64BIT
@@ -669,7 +712,7 @@ class ThreadStressLog {
long chunkListLength; // how many stress log chunks are in this stress log
#ifdef STRESS_LOG_READONLY
- FORCEINLINE StressMsg* AdvanceRead();
+ FORCEINLINE StressMsg* AdvanceRead(uint32_t cArgs);
#endif //STRESS_LOG_READONLY
FORCEINLINE StressMsg* AdvanceWrite(int cArgs);
@@ -804,7 +847,7 @@ class ThreadStressLog {
// Called while dumping. Returns true after all messages in log were dumped
FORCEINLINE BOOL CompletedDump ()
{
- return readPtr->timeStamp == 0
+ return readPtr->GetTimeStamp() == 0
//if read has passed end of list but write has not passed head of list yet, we are done
//if write has also wrapped, we are at the end if read pointer passed write pointer
|| (readHasWrapped &&
@@ -834,10 +877,10 @@ class ThreadStressLog {
// Called when dumping the log (by StressLog::Dump())
// Updates readPtr to point to next stress messaage to be dumped
// For convenience it returns the new value of readPtr
-inline StressMsg* ThreadStressLog::AdvanceRead() {
+inline StressMsg* ThreadStressLog::AdvanceRead(uint32_t cArgs) {
STATIC_CONTRACT_LEAF;
// advance the marker
- readPtr = (StressMsg*)((char*)readPtr + sizeof(StressMsg) + readPtr->numberOfArgs*sizeof(void*));
+ readPtr = (StressMsg*)((char*)readPtr + sizeof(StressMsg) + cArgs * sizeof(void*));
// wrap around if we need to
if (readPtr >= (StressMsg *)curReadChunk->EndPtr ())
{
diff --git a/src/shared/pal/prebuilt/inc/sospriv.h b/src/shared/pal/prebuilt/inc/sospriv.h
index cc34480996..c5dd1d488e 100644
--- a/src/shared/pal/prebuilt/inc/sospriv.h
+++ b/src/shared/pal/prebuilt/inc/sospriv.h
@@ -2621,7 +2621,7 @@ EXTERN_C const IID IID_ISOSDacInterface8;
ISOSDacInterface8 * This,
CLRDATA_ADDRESS methodTable,
CLRDATA_ADDRESS *assemblyLoadContext);
-
+
END_INTERFACE
} ISOSDacInterface8Vtbl;
@@ -2674,9 +2674,9 @@ EXTERN_C const IID IID_ISOSDacInterface8;
/* interface __MIDL_itf_sospriv_0000_0012 */
-/* [local] */
+/* [local] */
-#define SOS_BREAKING_CHANGE_VERSION 3
+#define SOS_BREAKING_CHANGE_VERSION 4
extern RPC_IF_HANDLE __MIDL_itf_sospriv_0000_0012_v0_0_c_ifspec;
@@ -2686,45 +2686,45 @@ extern RPC_IF_HANDLE __MIDL_itf_sospriv_0000_0012_v0_0_s_ifspec;
#define __ISOSDacInterface9_INTERFACE_DEFINED__
/* interface ISOSDacInterface9 */
-/* [uuid][local][object] */
+/* [uuid][local][object] */
EXTERN_C const IID IID_ISOSDacInterface9;
#if defined(__cplusplus) && !defined(CINTERFACE)
-
+
MIDL_INTERFACE("4eca42d8-7e7b-4c8a-a116-7bfbf6929267")
ISOSDacInterface9 : public IUnknown
{
public:
- virtual HRESULT STDMETHODCALLTYPE GetBreakingChangeVersion(
+ virtual HRESULT STDMETHODCALLTYPE GetBreakingChangeVersion(
int *pVersion) = 0;
-
+
};
-
-
+
+
#else /* C style interface */
typedef struct ISOSDacInterface9Vtbl
{
BEGIN_INTERFACE
-
- HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
ISOSDacInterface9 * This,
/* [in] */ REFIID riid,
- /* [annotation][iid_is][out] */
+ /* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject);
-
- ULONG ( STDMETHODCALLTYPE *AddRef )(
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
ISOSDacInterface9 * This);
-
- ULONG ( STDMETHODCALLTYPE *Release )(
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
ISOSDacInterface9 * This);
-
- HRESULT ( STDMETHODCALLTYPE *GetBreakingChangeVersion )(
+
+ HRESULT ( STDMETHODCALLTYPE *GetBreakingChangeVersion )(
ISOSDacInterface9 * This,
int *pVersion);
-
+
END_INTERFACE
} ISOSDacInterface9Vtbl;
@@ -2733,23 +2733,23 @@ EXTERN_C const IID IID_ISOSDacInterface9;
CONST_VTBL struct ISOSDacInterface9Vtbl *lpVtbl;
};
-
+
#ifdef COBJMACROS
#define ISOSDacInterface9_QueryInterface(This,riid,ppvObject) \
- ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
#define ISOSDacInterface9_AddRef(This) \
- ( (This)->lpVtbl -> AddRef(This) )
+ ( (This)->lpVtbl -> AddRef(This) )
#define ISOSDacInterface9_Release(This) \
- ( (This)->lpVtbl -> Release(This) )
+ ( (This)->lpVtbl -> Release(This) )
#define ISOSDacInterface9_GetBreakingChangeVersion(This,pVersion) \
- ( (This)->lpVtbl -> GetBreakingChangeVersion(This,pVersion) )
+ ( (This)->lpVtbl -> GetBreakingChangeVersion(This,pVersion) )
#endif /* COBJMACROS */
@@ -2764,91 +2764,91 @@ EXTERN_C const IID IID_ISOSDacInterface9;
#define __ISOSDacInterface10_INTERFACE_DEFINED__
/* interface ISOSDacInterface10 */
-/* [uuid][local][object] */
+/* [uuid][local][object] */
EXTERN_C const IID IID_ISOSDacInterface10;
#if defined(__cplusplus) && !defined(CINTERFACE)
-
+
MIDL_INTERFACE("90B8FCC3-7251-4B0A-AE3D-5C13A67EC9AA")
ISOSDacInterface10 : public IUnknown
{
public:
- virtual HRESULT STDMETHODCALLTYPE GetObjectComWrappersData(
+ virtual HRESULT STDMETHODCALLTYPE GetObjectComWrappersData(
CLRDATA_ADDRESS objAddr,
CLRDATA_ADDRESS *rcw,
unsigned int count,
CLRDATA_ADDRESS *mowList,
unsigned int *pNeeded) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE IsComWrappersCCW(
+
+ virtual HRESULT STDMETHODCALLTYPE IsComWrappersCCW(
CLRDATA_ADDRESS ccw,
BOOL *isComWrappersCCW) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE GetComWrappersCCWData(
+
+ virtual HRESULT STDMETHODCALLTYPE GetComWrappersCCWData(
CLRDATA_ADDRESS ccw,
CLRDATA_ADDRESS *managedObject,
int *refCount) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE IsComWrappersRCW(
+
+ virtual HRESULT STDMETHODCALLTYPE IsComWrappersRCW(
CLRDATA_ADDRESS rcw,
BOOL *isComWrappersRCW) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE GetComWrappersRCWData(
+
+ virtual HRESULT STDMETHODCALLTYPE GetComWrappersRCWData(
CLRDATA_ADDRESS rcw,
CLRDATA_ADDRESS *identity) = 0;
-
+
};
-
-
+
+
#else /* C style interface */
typedef struct ISOSDacInterface10Vtbl
{
BEGIN_INTERFACE
-
- HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
ISOSDacInterface10 * This,
/* [in] */ REFIID riid,
- /* [annotation][iid_is][out] */
+ /* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject);
-
- ULONG ( STDMETHODCALLTYPE *AddRef )(
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
ISOSDacInterface10 * This);
-
- ULONG ( STDMETHODCALLTYPE *Release )(
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
ISOSDacInterface10 * This);
-
- HRESULT ( STDMETHODCALLTYPE *GetObjectComWrappersData )(
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectComWrappersData )(
ISOSDacInterface10 * This,
CLRDATA_ADDRESS objAddr,
CLRDATA_ADDRESS *rcw,
unsigned int count,
CLRDATA_ADDRESS *mowList,
unsigned int *pNeeded);
-
- HRESULT ( STDMETHODCALLTYPE *IsComWrappersCCW )(
+
+ HRESULT ( STDMETHODCALLTYPE *IsComWrappersCCW )(
ISOSDacInterface10 * This,
CLRDATA_ADDRESS ccw,
BOOL *isComWrappersCCW);
-
- HRESULT ( STDMETHODCALLTYPE *GetComWrappersCCWData )(
+
+ HRESULT ( STDMETHODCALLTYPE *GetComWrappersCCWData )(
ISOSDacInterface10 * This,
CLRDATA_ADDRESS ccw,
CLRDATA_ADDRESS *managedObject,
int *refCount);
-
- HRESULT ( STDMETHODCALLTYPE *IsComWrappersRCW )(
+
+ HRESULT ( STDMETHODCALLTYPE *IsComWrappersRCW )(
ISOSDacInterface10 * This,
CLRDATA_ADDRESS rcw,
BOOL *isComWrappersRCW);
-
- HRESULT ( STDMETHODCALLTYPE *GetComWrappersRCWData )(
+
+ HRESULT ( STDMETHODCALLTYPE *GetComWrappersRCWData )(
ISOSDacInterface10 * This,
CLRDATA_ADDRESS rcw,
CLRDATA_ADDRESS *identity);
-
+
END_INTERFACE
} ISOSDacInterface10Vtbl;
@@ -2857,35 +2857,35 @@ EXTERN_C const IID IID_ISOSDacInterface10;
CONST_VTBL struct ISOSDacInterface10Vtbl *lpVtbl;
};
-
+
#ifdef COBJMACROS
#define ISOSDacInterface10_QueryInterface(This,riid,ppvObject) \
- ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
#define ISOSDacInterface10_AddRef(This) \
- ( (This)->lpVtbl -> AddRef(This) )
+ ( (This)->lpVtbl -> AddRef(This) )
#define ISOSDacInterface10_Release(This) \
- ( (This)->lpVtbl -> Release(This) )
+ ( (This)->lpVtbl -> Release(This) )
#define ISOSDacInterface10_GetObjectComWrappersData(This,objAddr,rcw,count,mowList,pNeeded) \
- ( (This)->lpVtbl -> GetObjectComWrappersData(This,objAddr,rcw,count,mowList,pNeeded) )
+ ( (This)->lpVtbl -> GetObjectComWrappersData(This,objAddr,rcw,count,mowList,pNeeded) )
#define ISOSDacInterface10_IsComWrappersCCW(This,ccw,isComWrappersCCW) \
- ( (This)->lpVtbl -> IsComWrappersCCW(This,ccw,isComWrappersCCW) )
+ ( (This)->lpVtbl -> IsComWrappersCCW(This,ccw,isComWrappersCCW) )
#define ISOSDacInterface10_GetComWrappersCCWData(This,ccw,managedObject,refCount) \
- ( (This)->lpVtbl -> GetComWrappersCCWData(This,ccw,managedObject,refCount) )
+ ( (This)->lpVtbl -> GetComWrappersCCWData(This,ccw,managedObject,refCount) )
#define ISOSDacInterface10_IsComWrappersRCW(This,rcw,isComWrappersRCW) \
- ( (This)->lpVtbl -> IsComWrappersRCW(This,rcw,isComWrappersRCW) )
+ ( (This)->lpVtbl -> IsComWrappersRCW(This,rcw,isComWrappersRCW) )
#define ISOSDacInterface10_GetComWrappersRCWData(This,rcw,identity) \
- ( (This)->lpVtbl -> GetComWrappersRCWData(This,rcw,identity) )
+ ( (This)->lpVtbl -> GetComWrappersRCWData(This,rcw,identity) )
#endif /* COBJMACROS */
@@ -2901,60 +2901,60 @@ EXTERN_C const IID IID_ISOSDacInterface10;
#define __ISOSDacInterface11_INTERFACE_DEFINED__
/* interface ISOSDacInterface11 */
-/* [uuid][local][object] */
+/* [uuid][local][object] */
EXTERN_C const IID IID_ISOSDacInterface11;
#if defined(__cplusplus) && !defined(CINTERFACE)
-
+
MIDL_INTERFACE("96BA1DB9-14CD-4492-8065-1CAAECF6E5CF")
ISOSDacInterface11 : public IUnknown
{
public:
- virtual HRESULT STDMETHODCALLTYPE IsTrackedType(
+ virtual HRESULT STDMETHODCALLTYPE IsTrackedType(
CLRDATA_ADDRESS objAddr,
BOOL *isTrackedType,
BOOL *hasTaggedMemory) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE GetTaggedMemory(
+
+ virtual HRESULT STDMETHODCALLTYPE GetTaggedMemory(
CLRDATA_ADDRESS objAddr,
CLRDATA_ADDRESS *taggedMemory,
size_t *taggedMemorySizeInBytes) = 0;
-
+
};
-
-
+
+
#else /* C style interface */
typedef struct ISOSDacInterface11Vtbl
{
BEGIN_INTERFACE
-
- HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
ISOSDacInterface11 * This,
/* [in] */ REFIID riid,
- /* [annotation][iid_is][out] */
+ /* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject);
-
- ULONG ( STDMETHODCALLTYPE *AddRef )(
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
ISOSDacInterface11 * This);
-
- ULONG ( STDMETHODCALLTYPE *Release )(
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
ISOSDacInterface11 * This);
-
- HRESULT ( STDMETHODCALLTYPE *IsTrackedType )(
+
+ HRESULT ( STDMETHODCALLTYPE *IsTrackedType )(
ISOSDacInterface11 * This,
CLRDATA_ADDRESS objAddr,
BOOL *isTrackedType,
BOOL *hasTaggedMemory);
-
- HRESULT ( STDMETHODCALLTYPE *GetTaggedMemory )(
+
+ HRESULT ( STDMETHODCALLTYPE *GetTaggedMemory )(
ISOSDacInterface11 * This,
CLRDATA_ADDRESS objAddr,
CLRDATA_ADDRESS *taggedMemory,
size_t *taggedMemorySizeInBytes);
-
+
END_INTERFACE
} ISOSDacInterface11Vtbl;
@@ -2963,26 +2963,26 @@ EXTERN_C const IID IID_ISOSDacInterface11;
CONST_VTBL struct ISOSDacInterface11Vtbl *lpVtbl;
};
-
+
#ifdef COBJMACROS
#define ISOSDacInterface11_QueryInterface(This,riid,ppvObject) \
- ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
#define ISOSDacInterface11_AddRef(This) \
- ( (This)->lpVtbl -> AddRef(This) )
+ ( (This)->lpVtbl -> AddRef(This) )
#define ISOSDacInterface11_Release(This) \
- ( (This)->lpVtbl -> Release(This) )
+ ( (This)->lpVtbl -> Release(This) )
#define ISOSDacInterface11_IsTrackedType(This,objAddr,isTrackedType,hasTaggedMemory) \
- ( (This)->lpVtbl -> IsTrackedType(This,objAddr,isTrackedType,hasTaggedMemory) )
+ ( (This)->lpVtbl -> IsTrackedType(This,objAddr,isTrackedType,hasTaggedMemory) )
#define ISOSDacInterface11_GetTaggedMemory(This,objAddr,taggedMemory,taggedMemorySizeInBytes) \
- ( (This)->lpVtbl -> GetTaggedMemory(This,objAddr,taggedMemory,taggedMemorySizeInBytes) )
+ ( (This)->lpVtbl -> GetTaggedMemory(This,objAddr,taggedMemory,taggedMemorySizeInBytes) )
#endif /* COBJMACROS */
@@ -2995,47 +2995,47 @@ EXTERN_C const IID IID_ISOSDacInterface11;
#define __ISOSDacInterface12_INTERFACE_DEFINED__
/* interface ISOSDacInterface12 */
-/* [uuid][local][object] */
+/* [uuid][local][object] */
EXTERN_C const IID IID_ISOSDacInterface12;
#if defined(__cplusplus) && !defined(CINTERFACE)
-
+
MIDL_INTERFACE("1b93bacc-8ca4-432d-943a-3e6e7ec0b0a3")
ISOSDacInterface12 : public IUnknown
{
public:
- virtual HRESULT STDMETHODCALLTYPE GetGlobalAllocationContext(
+ virtual HRESULT STDMETHODCALLTYPE GetGlobalAllocationContext(
CLRDATA_ADDRESS *allocPtr,
CLRDATA_ADDRESS *allocLimit) = 0;
-
+
};
-
-
+
+
#else /* C style interface */
typedef struct ISOSDacInterface12Vtbl
{
BEGIN_INTERFACE
-
- HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
ISOSDacInterface12 * This,
/* [in] */ REFIID riid,
- /* [annotation][iid_is][out] */
+ /* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject);
-
- ULONG ( STDMETHODCALLTYPE *AddRef )(
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
ISOSDacInterface12 * This);
-
- ULONG ( STDMETHODCALLTYPE *Release )(
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
ISOSDacInterface12 * This);
-
- HRESULT ( STDMETHODCALLTYPE *GetGlobalAllocationContext )(
+
+ HRESULT ( STDMETHODCALLTYPE *GetGlobalAllocationContext )(
ISOSDacInterface12 * This,
CLRDATA_ADDRESS *allocPtr,
CLRDATA_ADDRESS *allocLimit);
-
+
END_INTERFACE
} ISOSDacInterface12Vtbl;
@@ -3044,23 +3044,23 @@ EXTERN_C const IID IID_ISOSDacInterface12;
CONST_VTBL struct ISOSDacInterface12Vtbl *lpVtbl;
};
-
+
#ifdef COBJMACROS
#define ISOSDacInterface12_QueryInterface(This,riid,ppvObject) \
- ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
#define ISOSDacInterface12_AddRef(This) \
- ( (This)->lpVtbl -> AddRef(This) )
+ ( (This)->lpVtbl -> AddRef(This) )
#define ISOSDacInterface12_Release(This) \
- ( (This)->lpVtbl -> Release(This) )
+ ( (This)->lpVtbl -> Release(This) )
#define ISOSDacInterface12_GetGlobalAllocationContext(This,allocPtr,allocLimit) \
- ( (This)->lpVtbl -> GetGlobalAllocationContext(This,allocPtr,allocLimit) )
+ ( (This)->lpVtbl -> GetGlobalAllocationContext(This,allocPtr,allocLimit) )
#endif /* COBJMACROS */
@@ -3072,73 +3072,73 @@ EXTERN_C const IID IID_ISOSDacInterface12;
#endif /* __ISOSDacInterface12_INTERFACE_DEFINED__ */
-
+
#ifndef __ISOSDacInterface13_INTERFACE_DEFINED__
#define __ISOSDacInterface13_INTERFACE_DEFINED__
/* interface ISOSDacInterface13 */
-/* [uuid][local][object] */
+/* [uuid][local][object] */
EXTERN_C const IID IID_ISOSDacInterface13;
#if defined(__cplusplus) && !defined(CINTERFACE)
-
+
MIDL_INTERFACE("3176a8ed-597b-4f54-a71f-83695c6a8c5d")
ISOSDacInterface13 : public IUnknown
{
public:
- virtual HRESULT STDMETHODCALLTYPE TraverseLoaderHeap(
+ virtual HRESULT STDMETHODCALLTYPE TraverseLoaderHeap(
CLRDATA_ADDRESS loaderHeapAddr,
LoaderHeapKind kind,
VISITHEAP pCallback) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE GetDomainLoaderAllocator(
+
+ virtual HRESULT STDMETHODCALLTYPE GetDomainLoaderAllocator(
CLRDATA_ADDRESS domainAddress,
CLRDATA_ADDRESS *pLoaderAllocator) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeapNames(
+
+ virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeapNames(
int count,
const char **ppNames,
int *pNeeded) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeaps(
+
+ virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeaps(
CLRDATA_ADDRESS loaderAllocator,
int count,
CLRDATA_ADDRESS *pLoaderHeaps,
LoaderHeapKind *pKinds,
int *pNeeded) = 0;
};
-
-
+
+
#else /* C style interface */
typedef struct ISOSDacInterface13Vtbl
{
BEGIN_INTERFACE
-
+
DECLSPEC_XFGVIRT(IUnknown, QueryInterface)
- HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
ISOSDacInterface13 * This,
/* [in] */ REFIID riid,
- /* [annotation][iid_is][out] */
+ /* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject);
-
+
DECLSPEC_XFGVIRT(IUnknown, AddRef)
- ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
ISOSDacInterface13 * This);
-
+
DECLSPEC_XFGVIRT(IUnknown, Release)
- ULONG ( STDMETHODCALLTYPE *Release )(
+ ULONG ( STDMETHODCALLTYPE *Release )(
ISOSDacInterface13 * This);
-
+
DECLSPEC_XFGVIRT(ISOSDacInterface13, TraverseLoaderHeap)
- HRESULT ( STDMETHODCALLTYPE *TraverseLoaderHeap )(
+ HRESULT ( STDMETHODCALLTYPE *TraverseLoaderHeap )(
ISOSDacInterface13 * This,
CLRDATA_ADDRESS loaderHeapAddr,
LoaderHeapKind kind,
VISITHEAP pCallback);
-
+
END_INTERFACE
} ISOSDacInterface13Vtbl;
@@ -3147,23 +3147,23 @@ EXTERN_C const IID IID_ISOSDacInterface13;
CONST_VTBL struct ISOSDacInterface13Vtbl *lpVtbl;
};
-
+
#ifdef COBJMACROS
#define ISOSDacInterface13_QueryInterface(This,riid,ppvObject) \
- ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
#define ISOSDacInterface13_AddRef(This) \
- ( (This)->lpVtbl -> AddRef(This) )
+ ( (This)->lpVtbl -> AddRef(This) )
#define ISOSDacInterface13_Release(This) \
- ( (This)->lpVtbl -> Release(This) )
+ ( (This)->lpVtbl -> Release(This) )
#define ISOSDacInterface13_TraverseLoaderHeap(This,loaderHeapAddr,kind,pCallback) \
- ( (This)->lpVtbl -> TraverseLoaderHeap(This,loaderHeapAddr,kind,pCallback) )
+ ( (This)->lpVtbl -> TraverseLoaderHeap(This,loaderHeapAddr,kind,pCallback) )
#endif /* COBJMACROS */
diff --git a/src/tests/DbgShim.UnitTests/Debuggees/SimpleDebuggee/runtimeconfig.template.json b/src/tests/DbgShim.UnitTests/Debuggees/SimpleDebuggee/runtimeconfig.template.json
index f022b7ffce..8c606df890 100644
--- a/src/tests/DbgShim.UnitTests/Debuggees/SimpleDebuggee/runtimeconfig.template.json
+++ b/src/tests/DbgShim.UnitTests/Debuggees/SimpleDebuggee/runtimeconfig.template.json
@@ -1,3 +1,3 @@
{
- "rollForwardOnNoCandidateFx": 2
-}
\ No newline at end of file
+ "rollForward": "major"
+}
diff --git a/src/tests/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClientApiShim.cs b/src/tests/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClientApiShim.cs
index 23448c4638..21aa5a6e4a 100644
--- a/src/tests/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClientApiShim.cs
+++ b/src/tests/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClientApiShim.cs
@@ -88,5 +88,31 @@ public async Task StartEventPipeSession(EventPipeProvider prov
return _client.StartEventPipeSession(provider);
}
}
+
+ public async Task EnablePerfMap(PerfMapType type, TimeSpan timeout)
+ {
+ if (_useAsync)
+ {
+ using CancellationTokenSource cancellation = new(timeout);
+ await _client.EnablePerfMapAsync(type, cancellation.Token).ConfigureAwait(false);
+ }
+ else
+ {
+ _client.EnablePerfMap(type);
+ }
+ }
+
+ public async Task DisablePerfMap(TimeSpan timeout)
+ {
+ if (_useAsync)
+ {
+ using CancellationTokenSource cancellation = new(timeout);
+ await _client.DisablePerfMapAsync(cancellation.Token).ConfigureAwait(false);
+ }
+ else
+ {
+ _client.DisablePerfMap();
+ }
+ }
}
}
diff --git a/src/tests/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClientApiShimExtensions.cs b/src/tests/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClientApiShimExtensions.cs
index dce5050599..dc5492e5fe 100644
--- a/src/tests/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClientApiShimExtensions.cs
+++ b/src/tests/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClientApiShimExtensions.cs
@@ -36,5 +36,15 @@ public static Task StartEventPipeSession(this DiagnosticsClien
{
return shim.StartEventPipeSession(provider, DefaultPositiveVerificationTimeout);
}
+
+ public static Task EnablePerfMap(this DiagnosticsClientApiShim shim, PerfMapType type)
+ {
+ return shim.EnablePerfMap(type, DefaultPositiveVerificationTimeout);
+ }
+
+ public static Task DisablePerfMap(this DiagnosticsClientApiShim shim)
+ {
+ return shim.DisablePerfMap(DefaultPositiveVerificationTimeout);
+ }
}
}
diff --git a/src/tests/Microsoft.Diagnostics.NETCore.Client/PerfMapTests.cs b/src/tests/Microsoft.Diagnostics.NETCore.Client/PerfMapTests.cs
new file mode 100644
index 0000000000..501a7ad98f
--- /dev/null
+++ b/src/tests/Microsoft.Diagnostics.NETCore.Client/PerfMapTests.cs
@@ -0,0 +1,307 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Diagnostics.CommonTestRunner;
+using Microsoft.Diagnostics.TestHelpers;
+using Xunit;
+using Xunit.Abstractions;
+using Xunit.Extensions;
+using TestRunner = Microsoft.Diagnostics.CommonTestRunner.TestRunner;
+
+namespace Microsoft.Diagnostics.NETCore.Client
+{
+ public class PerMapTests
+ {
+ private readonly ITestOutputHelper _output;
+
+ public static IEnumerable