Intel x86提供的Branch Trace Store的功能

本文介绍了Intel x86架构中的Branch Trace Store(BTS)功能,及其在Win32环境下的启用和应用。BTS能够记录CPU执行的分支指令信息,帮助进行性能分析。文章详细阐述了BTS的工作框架,包括Last Branch Record、Branch Trace Messages和Branch Trace Store,并着重讲解了在Windows环境下开启BTS、设置DS_BUFFER_MGR_BLOCK、编写中断服务程序以及管理Performance Mon. Counter寄存器的步骤。此外,还提到了多核环境下和线程分析的相关问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写给转载者:

转载请保留作者信息

来源: http://www.csksoft.net/blog

作者:陈士凯

介绍

Branch Trace Store(BTS)是目前广泛被intel CPU所提供的一种硬件辅助调试功能,因为在MSRA项目需要,所以作了一些基于它的应用。虽然Intel的CPU开发手册[1]提供了比较详细的使用方法,但是由于比较笼统,且缺少win32下的相关资料。所以我打算把其中的一些tricky的事情和大家分享下。这些内容当然也是我自己查找公开资料得到的,因此也不算什么秘密吧 :-)

 

BTS简单的说就是允许CPU将自己实际执行到的分支指令(jmp/jxx/call/int/etc.)的相关信息保存下来的功能。一般CPU都会保存每个分支指令的源地址和目标地址,该地址在保护模式下是虚拟地址形式表示的。利用这个功能,可以实时地了解当前CPU正在执行代码的实际流程情况,很多分析软件,如Intel的Vtune或者profiling库,如*nix平台下的perfmon[2]都用它来做一些程序性能分析。当然,还可以做很多其他有趣的事,比如逆向工程,具体我就不说了。

 

不过目前很少有资料具体介绍如何在win32下开启该功能并实现一个可用的BTS捕捉引擎。当然可以参考perfmon的代码,但BTS在其中只是很小一个部分,同时为了实现跨平台,对于新手来说难度较大。因此我这里重点介绍对于单核心的NetBurst构架的CPU(通俗地说就是P4这类)在win32下的具体实现细节。其他的构架,比如现在的Core Due,大家可以参考intel的开发手册举一反三。

 

工作框架

实际上,上面所说的BTS只是intel对于分支指令信息捕获机制的一个分支,就P4而言,大致提供了下列几种分支指令的捕获手段

Last Branch Record(LBR)

故名思意,该方式将记录最后几个分支信息,实际上NetBurst CPU中内建了若干个MSR寄存器用于记录Last Branch Record,称为LBR Stack。在该模式下运行的CPU会采用Round Robin的方式循环填充那几个MSR寄存器。

该方式常用在调试器的Call Stack分析上,我们这里就不涉及了

 

Branch Trace Messages

该方式和我们将介绍的Branch Trace Store大致类似,与LBR不同的是,CPU会把分支信息发送到系统总线上供第三方硬件在总线上接收数据。而BTS则直接将数据保存到由程序制定的内存单元中。我们这里也不讨论该方式。

 

Branch Trace Store

简单的说,BTS就是将分支信息保存到了有程序(实际就是我们)制定的一块内存空间中。而当这块内存用尽时,CPU可以采用Round Robin的方式循环填充,这就和LBR类似,但可以指定内存块的大小来决定最大捕捉量。另一种处理方式是在内存快用尽的时候,一个事先由我们设定的处理中断将触发来完成对当前内存块中BTS数据的保存工作。这样就可以记录任意多的分支信息了。我们这里主要考虑的就是这种方式的BTS。

 

 

按照intel开发手册的描述,BTS开启后的CPU执行模式如下图所示:

 

每当CPU执行到一个分支指令后,它就会产生一个如上左图的BTS记录项。这里举个例子:

0x80001234   mov eax,[esp]

0x80001238   or eax,eax

0x80001240   jnz 0x80002000

0x80001245   nop

...

 

当执行上面这段执行,其中遇到了jnz指令,如果他的跳转条件成立,那么将产生一个从0x80001240到0x80002000的跳转,那么产生的BTS记录项就是{From:0x80001240,To:0x80002000,...}

 

对于P4的CPU,这个BTS记录项的结构如下:

struct BTS_ITEM_BLOCK_P4{     ULONG   dwBranchFrom;     ULONG   dwBranchTo;     ULONG   dwFlags; };

每次CPU执行到分支指令的时候,只要BTS开启,它就会产生一个如上结构得数据块,然后把它存储到事先定义好的一块内存当中去。而这块内存是比较灵活的,如上图所示,CPU需要知道这块内存的起始地址、结束地址、以及当记录到第几个记录时候需要触发一个中断程序来负责将现有的BTS记录保存下来防止内存溢出。当BTS记录存储到图中那个灰底色的“BTS记录#m”时,就会触发中断,可以发现它往往并不是整块记录内存

<think>我们正在处理用户的问题:如何在Gitee上创建一个新的C#项目仓库? 根据引用内容,我们了解到在Gitee上创建仓库的基本步骤,包括创建本地仓库、添加文件、提交并推送到远程仓库。 但是用户明确提到是C#项目,所以我们需要考虑C#项目的特点,比如通常会有.sln文件等,但创建仓库的过程与语言无关,主要步骤是相似的。 因此,我们将步骤分为两个部分:1.在Gitee网站上创建仓库;2.将本地C#项目推送到该仓库(或者初始化一个C#项目并推送)。 注意:用户可能没有现成的项目,所以我们可以提供两种情况的指导: 情况1:用户已经有一个本地的C#项目,需要推送到Gitee上新建的仓库。 情况2:用户还没有项目,需要从零开始创建一个C#项目并推送到Gitee。 由于引用中主要描述了推送已有仓库或新建仓库的命令行操作,我们将结合这些命令,并补充C#项目可能需要的特定步骤(如忽略文件等)。 步骤概览: 1. 在Gitee网站上创建新仓库(通过网页操作) 2. 初始化本地仓库(如果项目不存在,则先创建C#项目) 3. 将本地项目与远程仓库关联 4. 提交并推送代码 详细步骤: 一、在Gitee网站上创建仓库 1. 登录Gitee(https://gitee.com) 2. 点击右上角的“+”号,选择“新建仓库” 3. 填写仓库信息: - 仓库名称(例如:my-csharp-project) - 仓库介绍(可选) - 仓库是否公开(根据需求选择) - 其他选项(如初始化仓库时添加README、.gitignore等,建议至少添加一个.gitignore模板,选择VisualStudio) 4. 点击“创建”按钮 二、本地操作(两种情况) 情况1:用户还没有本地C#项目 1. 创建项目目录并初始化项目: - 打开命令行,进入工作目录 - 创建项目目录:`mkdir my-csharp-project` - 进入目录:`cd my-csharp-project` - 初始化一个新的C#控制台项目(假设已安装.NET SDK): ```bash dotnet new console ``` 这将创建一个简单的控制台程序,包含Program.cs和项目文件(.csproj)。 2. 初始化Git仓库: ```bash git init ``` 3. 添加.gitignore文件(如果之前在Gitee创建仓库时没有添加,这里需要手动添加): 对于C#项目,我们通常忽略bin、obj等目录。可以创建一个.gitignore文件,内容如下: ``` [Bb]in/ [Oo]bj/ .vs/ *.user *.suo *.cache *.log ``` 或者从网上下载一个标准的VisualStudio.gitignore文件。 4. 将文件添加到暂存区并提交: ```bash git add . git commit -m "Initial commit" ``` 情况2:用户已有本地C#项目 1. 进入项目根目录(确保该目录下没有.git目录,如果有,说明已经是仓库,可以跳过初始化步骤,但需要检查远程仓库设置) 2. 如果项目还不是Git仓库,执行: ```bash git init ``` 3. 检查.gitignore文件是否存在且正确,如果没有,则创建(内容同上)。 4. 添加并提交: ```bash git add . git commit -m "Initial commit" ``` 三、关联远程仓库并推送 1. 添加远程仓库地址(替换成你的仓库URL): ```bash git remote add origin https://gitee.com/your-username/your-repo-name.git ``` 注意:URL可以在Gitee仓库页面的“克隆/下载”按钮处获取。 2. 推送代码到远程仓库(首次推送需要加-u参数): ```bash git push -u origin master ``` 注意:如果Gitee上创建仓库时选择了初始化README文件,那么远程仓库已经有一个commit,此时直接推送可能会因为历史不同而被拒绝。有两种解决方法: a) 强制推送(不推荐,因为会覆盖远程的README):`git push -u origin master -f` b) 先拉取远程仓库,合并(推荐): ```bash git pull origin master --allow-unrelated-histories # 解决可能出现的合并冲突(比如README文件),然后再次提交 git push -u origin master ``` 但是,根据引用[2]和[3]中的命令,他们并没有提到拉取合并,而是直接推送。所以如果我们没有在远程仓库初始化任何文件(比如README、.gitignore),那么直接推送即可。因此,建议用户在Gitee创建仓库时不要勾选“初始化仓库”的选项(除了.gitignore可以选择,但也可以本地创建),这样就不会产生冲突。 因此,更简单的做法是:在Gitee创建仓库时,不要勾选“使用Readme文件初始化仓库”和“设置模板”(或者只勾选.gitignore模板,因为本地没有这个文件,不会冲突),然后按照上述步骤推送。 四、验证 推送完成后,刷新Gitee仓库页面,应该能看到上传的C#项目文件。 注意事项: - 如果使用VisualStudio创建项目,项目目录中可能已经包含.gitignore文件(取决于创建时的选项),请检查并确保它包含了必要的忽略规则。 - 在推送之前,确保提交了所有必要的文件,并且没有提交敏感信息(如密码、密钥等)。 根据上述步骤,我们给出一个完整的示例流程(以情况1为例,从零开始): 1. 在Gitee网站创建仓库,不勾选“使用Readme文件初始化仓库”,但.gitignore模板选择VisualStudio(这样会创建一个标准的.gitignore文件,避免用户自己写)。 2. 本地创建项目: mkdir my-csharp-app cd my-csharp-app dotnet new console 3. 初始化Git仓库: git init 4. 由于Gitee上已经创建了.gitignore,我们需要先拉取(但此时远程仓库还没有其他分支,所以需要先设置远程仓库然后拉取)? 但是,我们还没有关联远程仓库,所以先关联: git remote add origin https://gitee.com/your-username/my-csharp-app.git 5. 拉取远程仓库(因为远程仓库有.gitignore文件,而我们本地没有): git pull origin master 这时,远程的.gitignore文件会被拉取到本地。 6. 然后,将本地创建的项目文件(除了被忽略的)加入暂存区: git add . 7. 提交: git commit -m "Add C# project files" 8. 推送: git push -u origin master 但是,注意:步骤5拉取时,因为本地有文件(dotnet new console创建的文件)而远程也有文件(.gitignore),所以需要确保拉取不会冲突。实际上,这两个文件是不同的,所以拉取后会自动合并。然后我们再将项目文件加入,再提交。 另一种做法(更简单): 在Gitee创建仓库时,只选择.gitignore模板(不选README),然后我们本地创建项目,然后手动创建.gitignore文件(内容与Gitee提供的模板一致),这样就不用先拉取。然后直接提交推送。 为了简化,我们推荐用户使用以下步骤(避免拉取合并): 1. 在Gitee创建仓库时,只选择“使用.gitignore模板”并选择VisualStudio,其他不选。 2. 本地创建C#项目(在空目录中): dotnet new console 3. 从Gitee仓库页面复制.gitignore文件的内容(在仓库创建后,页面会显示该文件),然后在项目根目录创建.gitignore文件,粘贴内容。 4. 初始化本地仓库: git init git add . git commit -m "Initial commit" 5. 关联远程仓库并推送: git remote add origin <仓库URL> git push -u origin master 这样就不会有冲突,因为远程仓库只有.gitignore,而本地在提交前已经创建了相同的.gitignore文件(内容相同),所以推送时不会冲突。 但是,注意:如果远程仓库创建时生成的.gitignore文件内容与本地手动创建的可能有差异?为了避免差异,我们可以先拉取.gitignore文件,然后再添加项目文件。不过对于简单的项目,手动创建也是可以的。 考虑到用户可能对Git操作不熟悉,我们提供第二种方法(手动创建.gitignore)可能更直观。 因此,我们总结一个推荐步骤: 步骤1:在Gitee网站创建仓库 - 填写仓库名称 - 选择“使用.gitignore模板” -> VisualStudio - 不要勾选“使用Readme文件初始化仓库” - 创建仓库 步骤2:本地操作 - 创建项目目录,进入 - 创建C#项目:`dotnet new console` - 初始化Git:`git init` - 将远程仓库的.gitignore文件内容复制到本地的.gitignore文件中(可以通过在Gitee仓库页面查看该文件,点击“原始”获取链接,然后用curl下载,或者手动创建并复制内容) 例如,使用curl(如果安装了): curl -o .gitignore https://gitee.com/your-username/your-repo-name/raw/master/.gitignore 注意:将URL替换成你仓库的.gitignore文件原始数据URL(在仓库页面点击.gitignore文件,然后点击“原始”按钮,复制地址) 或者,手动创建:在项目根目录新建一个名为.gitignore的文件,复制以下内容(标准的VisualStudio.gitignore): ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.rsuser *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Mono auto generated files mono_crash.* # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ [Ll]ogs/ # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # Visual Studio 2017 auto generated files Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUnit *.VisualState.xml TestResult.xml nunit-*.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # Benchmark Results BenchmarkDotNet.Artifacts/ # .NET Core project.lock.json project.fragment.lock.json artifacts/ **/Properties/launchSettings.json # StyleCop StyleCopReport.xml # Files built by Visual Studio *_i.c *_p.c *_i.h *.ilk *.meta *.obj *.iobj *.pch *.pdb *.ipdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # Visual Studio Trace Files *.e2e # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # AxoCover is a Code Coverage Tool .axoCover/* !.axoCover/settings.json # Visual Studio code coverage results *.coverage *.coveragexml # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/[Pp]ackages/* # except build/, which is used as an MSBuild target. !**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/[Pp]ackages/repositories.config # NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt *.appx *.appxbundle *.appxupload # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !?*.[Cc]ache/ # Others ClientBin/ ~$* *~ *.dbmdl *.dbproj.schemaview *.jfm *.pfx *.publishsettings orleans.codegen.cs # Including strong name files can present a security risk # (https://github.com/github/gitignore/pull/2483#issue-259490424) #*.snk # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm ServiceFabricBackup/ *.rptproj.bak # SQL Server files *.mdf *.ldf *.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings *.rptproj.rsuser *.rptproj_rb.user # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat node_modules/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ # FAKE - F# Make .fake/ # CodeRush personal settings .cr/personal # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc # Cake - Uncomment if you are using it # tools/** # !tools/packages.config # Tabs Studio *.tss # Telerik's JustMock configuration file *.jmconfig # BizTalk build output *.btp.cs *.btm.cs *.odx.cs *.xsd.cs # OpenCover UI analysis results OpenCover/ # Azure Stream Analytics local run output ASALocalRun/ # MSBuild Binary and Structured Log *.binlog # NVidia Nsight GPU debugger configuration file *.nvuser # MFractors (Xamarin productivity tool) working folder .mfractor/ # Local History for Visual Studio .localhistory/ # BeatPulse healthcheck temp database healthchecksdb # Backup folder for Package Reference Convert tool in Visual Studio 2017 MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ # Fody - auto-generated XML schema FodyWeavers.xsd # VS Code files for those working on multiple tools .vscode/* !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json *.code-workspace # Local History for Visual Studio Code .history/ - 然后执行: git add . git commit -m "Initial commit" - 关联远程仓库(替换URL): git remote add origin https://gitee.com/your-username/your-repo-name.git - 推送: git push -u origin master 注意:如果用户使用的主分支是main(Gitee默认创建的是master,但也可以创建时选择main),则推送时使用main。 如果用户在Gitee创建仓库时选择了默认分支为main,那么命令应该是: git push -u origin main 但在初始化本地仓库时,默认分支可能是master(取决于Git版本和配置)。为了保持一致,可以在初始化本地仓库时设置分支名为main: git init -b main 或者,在推送前重命名本地分支: git branch -M main 然后推送: git push -u origin main 因此,我们建议用户注意Gitee仓库创建后显示的命令行指引,根据指引操作(因为Gitee会根据用户创建仓库时选择的分支给出相应的命令)。 最后,我们根据引用[1][2][3]的内容,结合C#项目的特点,给出了详细的步骤。用户可以根据自己的实际情况选择对应的步骤。 相关问题: 1. 如何解决推送时出现的“非快进式更新”错误? 2. 如何将现有的C#解决方案(包含多个项目)推送到Gitee仓库? 3. 在Gitee上创建仓库时,如何选择分支初始化(master/main)? 4. 如何配置Git忽略文件(.gitignore)以适用于C#项目? 5. 如何通过Visual Studio的图形界面将项目推送到Gitee? 注意:我们引用了三个引用,但引用内容主要是关于Git命令的,所以我们在回答中主要参考了这些命令,并结合了C#项目的特定需求(如.gitignore)。</think>### 如何在 Gitee 上创建新的 C# 项目仓库 以下是详细步骤(分网页操作和本地操作两部分): #### 一、Gitee 网页端操作 1. **登录 Gitee 账号** 访问 [gitee.com](https://gitee.com) 并登录。 2. **创建新仓库** - 点击右上角 ➕ 图标 → 选择「新建仓库」 - 填写仓库信息: - **仓库名称**:如 `csharp-project` - **仓库介绍**:可选填 - **可见性**:选择公开/私有 - **初始化设置**(关键步骤): - ☑️ **使用 .gitignore** → 选择 `VisualStudio`(自动忽略编译文件) - ☑️ **设置模板** → 选择 `C#`(可选) - ⬜ 不勾选「使用 Readme 文件初始化」(避免首次推送冲突) - 点击「创建仓库」 #### 二、本地操作(两种场景) ##### 场景1:新建 C# 项目 ```bash # 1. 创建项目目录 mkdir my-csharp-project cd my-csharp-project # 2. 初始化 C# 项目(需安装 .NET SDK) dotnet new console # 创建控制台项目 # 3. 初始化 Git 仓库 git init git checkout -b main # 创建分支(Gitee 默认主分支为 main) # 4. 关联远程仓库(替换成你的仓库URL) git remote add origin https://gitee.com/your-username/csharp-project.git # 5. 提交并推送 git add . git commit -m "初始化 C# 项目" git push -u origin main # 首次推送需加 -u ``` ##### 场景2:推送已有 C# 项目 ```bash # 进入项目根目录 cd existing-csharp-project # 初始化 Git 并关联远程仓库 git init git remote add origin https://gitee.com/your-username/csharp-project.git git add . git commit -m "首次提交" git push -u origin main ``` #### 关键注意事项 1. **.gitignore 配置** - 如果未通过网页初始化,需手动创建 `.gitignore` 文件并添加: ```gitignore [Bb]in/ [Oo]bj/ .vs/ *.user *.suo ``` - 避免提交编译文件和 IDE 临时文件[^2]。 2. **分支名称一致性** - Gitee 默认主分支为 `main`,若本地使用 `master`,需执行: ```bash git branch -m master main # 重命名分支 git push -u origin main ``` 3. **推送冲突处理** - 若网页端初始化了文件(如 README),需先拉取合并: ```bash git pull origin main --allow-unrelated-histories git push -u origin main ``` #### 验证成功 1. 刷新 Gitee 仓库页面,应显示 C# 项目文件 2. 确认 `.gitignore` 已生效(Bin/Obj 目录未上传) 3. 检查提交历史记录是否包含初始化信息 > 提示:首次推送后可在 Gitee 仓库的「设置」→「仓库管理」中配置协作权限、Webhook 等高级功能。 --- ### 相关问题 1. **如何解决推送时出现的 `.gitignore 不生效` 问题?** 2. **C# 项目应该忽略哪些文件/目录以优化仓库?** 3. **如何在 Visual Studio 中直接管理 Gitee 仓库?** 4. **如何将现有的 GitHub C# 项目迁移到 Gitee?** 5. **Gitee 仓库与 Azure DevOps 的 Git 管理有何差异?** [^1]: Gitee 官方文档 - 创建仓库流程 [^2]: Git 最佳实践 - 忽略规则配置 [^3]: .NET 项目标准忽略模板
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值