### DTrace Command-Line Usage Examples Source: https://context7.com/microsoft/dtrace-on-windows/llms.txt Demonstrates various command-line operations for DTrace on Windows, including listing probes, filtering, executing scripts, tracing processes, setting buffer sizes, and configuring output. These examples cover common scenarios for ad-hoc analysis and debugging. ```bash # List all available probes dtrace -l # List probes matching a pattern dtrace -l -n 'syscall::*Read*:entry' # Count probe matches dtrace -l -n 'fbt:ntfs::' | wc -l # Execute one-liner to trace syscalls for 5 seconds dtrace -n 'syscall:::entry { @[probefunc] = count(); } tick-5s { exit(0); }' # Run script from file dtrace -s myscript.d # Run script with arguments dtrace -s script.d 1234 "arg2" # Trace specific process by PID dtrace -p 1234 -s script.d # Launch and trace a command dtrace -c notepad.exe -n 'syscall:::entry { @[probefunc] = count(); }' # Set buffer size and output options dtrace -b 4m -s script.d # Use preprocessor on script dtrace -C -D DEBUG_MODE=1 -s script.d # Enable verbose error messages dtrace -v -s script.d # Quiet mode (suppress column headers) dtrace -q -s script.d # Generate anonymous tracing configuration dtrace -A -s script.d > dtrace.conf # Create object file for linking dtrace -G -s probes.d -o probes.o # Generate C header file dtrace -h -s probes.d ``` -------------------------------- ### Start Tracing and Consume Data with Callbacks in C Source: https://context7.com/microsoft/dtrace-on-windows/llms.txt This C code demonstrates how to start DTrace operations, process collected data using custom probe and record callbacks, and handle the tracing lifecycle. It includes functions for initializing tracing, consuming data, and stopping the trace. Dependencies include the DTrace library. ```c #include // Callback invoked for each probe that fires int probe_consumer(const dtrace_probedata_t *data, void *arg) { dtrace_probedesc_t *pd = data->dtpda_pdesc; printf("Probe fired: %s:%s:%s:%s on CPU %d\n", pd->dtpd_provider, pd->dtpd_mod, pd->dtpd_func, pd->dtpd_name, data->dtpda_cpu); return DTRACE_CONSUME_THIS; } // Callback invoked for each data record int record_consumer(const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg) { if (rec->dtrd_action == DTRACEACT_PRINTF) { // Handle printf output return DTRACE_CONSUME_THIS; } return DTRACE_CONSUME_THIS; } int start_tracing(dtrace_hdl_t *dtp) { int status; // Start DTrace data collection if (dtrace_go(dtp) != 0) { fprintf(stderr, "Failed to start tracing: %s\n", dtrace_errmsg(dtp, dtrace_errno(dtp))); return -1; } printf("Tracing started...\n"); // Main event loop: consume trace data do { // Process buffered trace data if (dtrace_consume(dtp, stdout, probe_consumer, record_consumer, NULL) == -1) { fprintf(stderr, "Error consuming data: %s\n", dtrace_errmsg(dtp, dtrace_errno(dtp))); break; } // Check tracing status status = dtrace_status(dtp); // Sleep until next data collection interval if (status == DTRACE_STATUS_NONE) { dtrace_sleep(dtp); } } while (status == DTRACE_STATUS_NONE || status == DTRACE_STATUS_OKAY); // Stop tracing dtrace_stop(dtp); if (status == DTRACE_STATUS_EXITED) { printf("Tracing completed successfully\n"); } return 0; } ``` -------------------------------- ### Error and Drop Handler Setup in C Source: https://context7.com/microsoft/dtrace-on-windows/llms.txt This C code shows how to register custom callbacks for handling DTrace errors and buffer drops. It defines functions to process error messages and dropped record warnings, allowing for robust tracing by providing feedback on potential issues. The DTrace library is a prerequisite. ```c #include // Error handler callback int handle_error(const dtrace_errdata_t *data, void *arg) { fprintf(stderr, "ERROR on CPU %d: %s\n", data->dteda_cpu, data->dteda_msg); if (data->dteda_pdesc) { fprintf(stderr, " Probe: %s:%s:%s:%s\n", data->dteda_pdesc->dtpd_provider, data->dteda_pdesc->dtpd_mod, data->dteda_pdesc->dtpd_func, data->dteda_pdesc->dtpd_name); } // Return DTRACE_HANDLE_OK to continue tracing return DTRACE_HANDLE_OK; } // Drop handler callback int handle_drop(const dtrace_dropdata_t *data, void *arg) { fprintf(stderr, "WARNING: Dropped %llu records on CPU %d: %s\n", data->dtdda_drops, data->dtdda_cpu, data->dtdda_msg); fprintf(stderr, " Total drops: %llu\n", data->dtdda_total); return DTRACE_HANDLE_OK; } int setup_handlers(dtrace_hdl_t *dtp) { // Register error handler if (dtrace_handle_err(dtp, handle_error, NULL) == -1) { fprintf(stderr, "Failed to register error handler\n"); return -1; } // Register drop handler if (dtrace_handle_drop(dtp, handle_drop, NULL) == -1) { fprintf(stderr, "Failed to register drop handler\n"); return -1; } printf("Error and drop handlers registered\n"); return 0; } ``` -------------------------------- ### DTrace - Trace NTFS Paths for Notepad Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/README.md This DTrace script traces file system operations (NTFS) specifically when 'notepad.exe' is running. It uses the 'fbt' (Function Boundary Tracing) provider for NTFS functions and filters by executable name. This example requires kernel debugging (KD) attachment and the target process to be launched after the script starts. ```dtrace dtrace -Fn "fbt:ntfs::/execname==\"notepad.exe\"/{}" ``` -------------------------------- ### Create Fasttrap Probes for Function Tracing with DTrace Source: https://context7.com/microsoft/dtrace-on-windows/llms.txt This section demonstrates how to use DTrace to create fasttrap probes for dynamically instrumenting function entry and return points in user-mode processes. Examples include tracing all functions, specific functions with arguments, and monitoring function duration. ```bash # Trace all functions in notepad.exe when it runs # Entry and return probes are created automatically dtrace -n 'pid$target:::entry { @calls[probefunc] = count(); }' \ -n 'tick-5s { printa(@calls); exit(0); }' \ -c notepad.exe # Trace specific function with arguments dtrace -n 'pid$target::CreateFileW:entry { printf("CreateFileW called with: %S", copyinwstr(arg0)); }' -p 1234 # Monitor function duration dtrace -n 'pid$target:::entry { self->ts = timestamp; }' \ -n 'pid$target:::return /self->ts/ { @elapsed[probefunc] = quantize(timestamp - self->ts); self->ts = 0; }' \ -n 'tick-10s { printa(@elapsed); exit(0); }' \ -p 1234 ``` -------------------------------- ### Monitor System Calls by Process with DTrace Source: https://context7.com/microsoft/dtrace-on-windows/llms.txt This group of DTrace commands shows how to track and summarize system call activity across the system. It includes examples for summarizing syscalls over a period, tracking specific syscall families, and monitoring failed syscalls with their status codes. ```bash # Summarize syscalls for 5 seconds dtrace -Fn 'tick-5sec { exit(0); } syscall:::entry { @num[pid, execname] = count(); }' # Track specific syscall families dtrace -Fn 'tick-3sec { exit(0); } syscall::Nt*Timer*:entry { @[probefunc, execname, pid] = count(); }' # Monitor failed syscalls with status codes dtrace -n 'syscall:::return /(uint32_t)arg0 != 0/ { @errors[execname, probefunc, arg0] = count(); }' \ -n 'tick-10s { printa(@errors); exit(0); }' ``` -------------------------------- ### Initialize Lexer State and Mode Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/lib/ucpp/README.md Initializes the lexer state and mode. `init_lexer_mode` should be called after `init_lexer_state` if token output is desired. ```c struct lexer_state state; init_lexer_state(&state); init_lexer_mode(&state); // If outputting tokens ``` -------------------------------- ### Initialize C Preprocessor and Lexer Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/lib/ucpp/README.md Initializes the lexer automaton for the C preprocessor. This function must be called before other initialization steps. ```c init_cpp(); ``` -------------------------------- ### Initialize DTrace Handle and Set Options (C) Source: https://context7.com/microsoft/dtrace-on-windows/llms.txt This C code snippet demonstrates how to initialize a DTrace handle using `dtrace_open` and configure tracing session options like buffer size and aggregation rate using `dtrace_setopt`. It includes error handling for initialization and option setting. The handle must be closed using `dtrace_close` when no longer needed. ```c #include int main() { dtrace_hdl_t *dtp; int err; // Open DTrace handle with default flags dtp = dtrace_open(DTRACE_VERSION, 0, &err); if (dtp == NULL) { fprintf(stderr, "Failed to initialize DTrace: %s\n", dtrace_errmsg(NULL, err)); return 1; } // Set options for the tracing session if (dtrace_setopt(dtp, "bufsize", "4m") != 0) { fprintf(stderr, "Failed to set bufsize: %s\n", dtrace_errmsg(dtp, dtrace_errno(dtp))); } if (dtrace_setopt(dtp, "aggrate", "1000us") != 0) { fprintf(stderr, "Failed to set aggrate: %s\n", dtrace_errmsg(dtp, dtrace_errno(dtp))); } // Use the handle for tracing operations... // Clean up when done dtrace_close(dtp); return 0; } ``` -------------------------------- ### Set Initial Filename for Preprocessing Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/lib/ucpp/README.md Sets the initial filename for the preprocessor. The second argument indicates if the filename is 'real' (i.e., can be opened). ```c set_init_filename("input.c", 1); // Real file set_init_filename("input.c", 0); // Conventional file ``` -------------------------------- ### Initialize Macro Table and Assertions Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/lib/ucpp/README.md Initializes the macro table and other internal structures. An optional argument can be used to initialize assertions. ```c init_tables(1); // Initialize assertions init_tables(0); // Do not initialize assertions ``` -------------------------------- ### Generate C Header from D Program using libdtrace Source: https://context7.com/microsoft/dtrace-on-windows/llms.txt Creates a C header file containing probe macros for static tracing. This function uses the libdtrace library to generate the header, enabling static inclusion of probe definitions in C/C++ source files. It requires a valid dtrace handle and writes to a specified file. ```c #include int generate_header(dtrace_hdl_t *dtp) { FILE *header_file; const char *provider_name = "myapp"; header_file = fopen("dtrace_probes.h", "w"); if (header_file == NULL) { perror("Failed to create header file"); return -1; } // Generate header with probe macros if (dtrace_program_header(dtp, header_file, provider_name) != 0) { fprintf(stderr, "Failed to generate header: %s\n", dtrace_errmsg(dtp, dtrace_errno(dtp))); fclose(header_file); return -1; } fclose(header_file); printf("Generated dtrace_probes.h\n"); // The header can now be included in your source code // and provides macros like: MYAPP_PROBE(name, args...) return 0; } ``` -------------------------------- ### Configure Output Emission Settings Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/lib/ucpp/README.md Sets global variables to control the emission of dependencies, macro definitions, assertions, and the output stream. ```c emit_dependencies = 1; emit_defines = 1; emit_assertions = 1; FILE *output_file = fopen("output.txt", "w"); if (output_file) { emit_output = output_file; } ``` -------------------------------- ### Process Aggregations with DTrace C API Source: https://context7.com/microsoft/dtrace-on-windows/llms.txt Demonstrates how to walk and process aggregated trace data collected by DTrace using its C API. This involves defining a callback function to iterate over aggregation data and then printing or clearing the aggregations. ```c #include // Aggregation walker callback int walk_aggregation(const dtrace_aggdata_t *agg, void *arg) { dtrace_aggdesc_t *aggdesc = agg->dtada_desc; dtrace_probedesc_t *pd = agg->dtada_pdesc; printf("Aggregation: @%s from %s:%s:%s:%s\n", aggdesc->dtagd_name, pd->dtpd_provider, pd->dtpd_mod, pd->dtpd_func, pd->dtpd_name); // Access aggregation data printf(" Data size: %zu bytes\n", agg->dtada_size); printf(" Normalization: %llu\n", agg->dtada_normal); if (agg->dtada_flags & DTRACE_A_PERCPU) { printf(" Per-CPU data available\n"); } return DTRACE_AGGWALK_NEXT; } int process_aggregations(dtrace_hdl_t *dtp) { // Walk all aggregations with sorted output if (dtrace_aggregate_walk_sorted(dtp, walk_aggregation, NULL) == -1) { fprintf(stderr, "Failed to walk aggregations: %s\n", dtrace_errmsg(dtp, dtrace_errno(dtp))); return -1; } // Print aggregations to file with default formatting FILE *outfile = fopen("aggregations.txt", "w"); if (outfile) { dtrace_aggregate_print(dtp, outfile, NULL); fclose(outfile); } // Clear aggregation data for next interval dtrace_aggregate_clear(dtp); return 0; } ``` -------------------------------- ### Link D Program to Object File with C API Source: https://context7.com/microsoft/dtrace-on-windows/llms.txt This C code snippet demonstrates how to link a D program to an ELF/COFF object file using the DTrace C API. The `dtrace_program_link` function is used to create an object file that can then be linked with an application and have its probes enabled at runtime. ```c #include int create_object_file(dtrace_hdl_t *dtp, dtrace_prog_t *prog) { const char *output_file = "dtrace_probes.o"; // Link program to ELF/COFF object file // DTRACE_D_STRIP: Remove non-loadable sections // DTRACE_D_PROBES: Include probe definitions if (dtrace_program_link(dtp, prog, DTRACE_D_STRIP | DTRACE_D_PROBES, output_file, 0, NULL) != 0) { fprintf(stderr, "Failed to link program: %s\n", dtrace_errmsg(dtp, dtrace_errno(dtp))); return -1; } printf("Successfully created object file: %s\n", output_file); // Can now link this .o file with your application // and enable probes at runtime return 0; } ``` -------------------------------- ### Compile and Execute D Script from String (C) Source: https://context7.com/microsoft/dtrace-on-windows/llms.txt This C code compiles a D language tracing script provided as a string using `dtrace_program_strcompile`. It then retrieves program information and enables the script for execution in the kernel using `dtrace_program_exec`. Error handling is included for compilation and execution steps. ```c #include int compile_and_execute_script(dtrace_hdl_t *dtp) { dtrace_prog_t *prog; dtrace_proginfo_t info; const char *script = "syscall::NtReadFile:entry { @bytes[execname] = sum(arg6); } " "tick-5s { printa(@bytes); exit(0); }"; // Compile the D script from a string prog = dtrace_program_strcompile(dtp, script, DTRACE_PROBESPEC_NAME, DTRACE_C_ZDEFS, 0, NULL); if (prog == NULL) { fprintf(stderr, "Compilation failed: %s\n", dtrace_errmsg(dtp, dtrace_errno(dtp))); return -1; } // Get information about the compiled program dtrace_program_info(dtp, prog, &info); printf("Program matched %d probes\n", info.dpi_matches); printf("Program has %d aggregates\n", info.dpi_aggregates); // Enable the program (load into kernel) if (dtrace_program_exec(dtp, prog, &info) == -1) { fprintf(stderr, "Failed to enable program: %s\n", dtrace_errmsg(dtp, dtrace_errno(dtp))); return -1; } printf("Program enabled with %d probes\n", info.dpi_matches); return 0; } ``` -------------------------------- ### Simplified Tracing with Work Loop in C Source: https://context7.com/microsoft/dtrace-on-windows/llms.txt This C code utilizes the DTrace work loop for simplified tracing, combining go, consume, and sleep operations into a single function call. It's useful for basic tracing scenarios where custom data consumption logic is not required. The DTrace library is a dependency. ```c #include int simple_trace_loop(dtrace_hdl_t *dtp) { dtrace_workstatus_t status; printf("Starting DTrace work loop...\n"); // dtrace_work() combines dtrace_go(), dtrace_consume(), // and dtrace_sleep() into a single call do { status = dtrace_work(dtp, stdout, NULL, NULL, NULL); if (status == DTRACE_WORKSTATUS_ERROR) { fprintf(stderr, "Error in work loop: %s\n", dtrace_errmsg(dtp, dtrace_errno(dtp))); return -1; } } while (status == DTRACE_WORKSTATUS_OKAY); printf("Tracing completed\n"); return 0; } ``` -------------------------------- ### Monitor File I/O by Process with DTrace Script (D) Source: https://context7.com/microsoft/dtrace-on-windows/llms.txt A DTrace script designed to monitor file read and write operations aggregated by process. It normalizes the data to show throughput in KB/s and displays the top 10 processes for both reads and writes every 3 seconds. ```d // D Script: file_io_monitor.d // Tracks file I/O operations and reports throughput every 3 seconds #pragma D option quiet #pragma D option destructive #pragma D option aggrate=1000us BEGIN { ts = timestamp; printf("Monitoring file I/O operations...\n"); } syscall::NtReadFile:entry { @read[execname, pid] = sum(arg6); @write[execname, pid] = sum(0); } syscall::NtWriteFile:entry { @write[execname, pid] = sum(arg6); @read[execname, pid] = sum(0); } tick-3s { system("cls"); // Keep only top 10 entries trunc(@read, 10); trunc(@write, 10); // Normalize to KB/s based on elapsed time fact = 1024 * (timestamp - ts) / 1000000000; normalize(@read, fact); normalize(@write, fact); printf("\n%-16s %16s %10s %10s\n", "Executable", "PID", "read[kb/s]", "write[kb/s]"); printa("%-16s %16d %@10d %@10d\n", @read, @write); clear(@read); clear(@write); ts = timestamp; } tick-30s { exit(0); } // Run with: dtrace -s file_io_monitor.d ``` -------------------------------- ### DTrace - Syscall Summary by Program Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/README.md This DTrace script summarizes system call counts by program (PID and executable name) for a duration of 5 seconds. It uses the 'tick' probe for time-based execution and filters syscall entries. No external dependencies are explicitly mentioned beyond the DTrace framework itself. ```dtrace dtrace -Fn "tick-5sec { exit(0);}\n syscall:::entry{ @num[pid,execname] = count();} " ``` -------------------------------- ### Compile and Execute D Script from File (C) Source: https://context7.com/microsoft/dtrace-on-windows/llms.txt This C code compiles a D tracing script from a file stream using `dtrace_program_fcompile`. After successful compilation, it executes the program using `dtrace_program_exec` and reports the number of matched probes and aggregates. The file is opened and closed within the function, and includes error handling for file operations and compilation/execution. ```c #include #include int compile_from_file(dtrace_hdl_t *dtp, const char *filename) { FILE *fp; dtrace_prog_t *prog; dtrace_proginfo_t info; // Open the D script file fp = fopen(filename, "r"); if (fp == NULL) { perror("Failed to open script file"); return -1; } // Compile from file stream prog = dtrace_program_fcompile(dtp, fp, DTRACE_C_ZDEFS | DTRACE_C_EATTR, 0, NULL); fclose(fp); if (prog == NULL) { fprintf(stderr, "Failed to compile %s: %s\n", filename, dtrace_errmsg(dtp, dtrace_errno(dtp))); return -1; } // Execute the compiled program if (dtrace_program_exec(dtp, prog, &info) == -1) { fprintf(stderr, "Failed to execute program: %s\n", dtrace_errmsg(dtp, dtrace_errno(dtp))); return -1; } printf("Successfully compiled and executed %s\n", filename); printf("Matched %d probes, %d aggregates\n", info.dpi_matches, info.dpi_aggregates); return 0; } ``` -------------------------------- ### Configure Global Variables for Preprocessor Behavior Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/lib/ucpp/README.md Sets global variables to control preprocessor behavior, such as handling of special macros, C99 compliance, and output emission. ```c no_special_macros = 1; c99_compliant = 1; c99_hosted = 0; emit_defines = 0; emit_assertions = 0; ``` -------------------------------- ### Configure Lexer Flags for C Preprocessing Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/lib/ucpp/README.md Adjusts the flags field of the `lexer_state` to control various preprocessing behaviors, including warnings, comment handling, and C99 compliance. ```c state.flags = WARN_STANDARD | CPLUSPLUS_COMMENTS | LINE_NUM; ``` -------------------------------- ### Access Windows Kernel Structures with DScript Source: https://context7.com/microsoft/dtrace-on-windows/llms.txt This D script accesses and displays working set information for a specified process ID on Windows. It requires symbol information to be available and can be run using the `dtrace` command with a process ID as an argument. ```d #pragma D option quiet #pragma D option destructive PLIST_ENTRY head; PLIST_ENTRY curptr; struct nt`_EPROCESS *eprocess_ptr; int found; BEGIN { head = (PLIST_ENTRY)&nt`PsActiveProcessHead; curptr = head->Flink; found = 0; printf("Looking for process %d...\n", $1); } tick-1ms / !found / { if (curptr == head) { exit(0); } // Calculate EPROCESS pointer from list entry eprocess_ptr = (struct nt`_EPROCESS*) ((intptr_t)curptr - offsetof(nt`_EPROCESS, ActiveProcessLinks)); processid = (int)eprocess_ptr->UniqueProcessId; if ($1 == processid) { found = 1; } else { curptr = curptr->Flink; } } tick-1s / found / { system("cls"); printf("Process: %s (PID: %d)\n", eprocess_ptr->ImageFileName, processid); printf("Working Set Size: %llu KB\n", (uint64_t)eprocess_ptr->Vm.Instance.WorkingSetSize * 4); printf("Private Working Set: %llu KB\n", (uint64_t)eprocess_ptr->Vm.Instance.WorkingSetLeafPrivateSize * 4); printf("Peak Working Set: %llu KB\n", (uint64_t)eprocess_ptr->Vm.Instance.PeakWorkingSetSize * 4); printf("Page Fault Count: %u\n", eprocess_ptr->Vm.Instance.PageFaultCount); printf("Hard Fault Count: %u\n", eprocess_ptr->Vm.Instance.HardFaultCount); printf("Virtual Size: %llu MB\n", (uint64_t)eprocess_ptr->VirtualSize / (1024*1024)); printf("Commit Charge: %llu KB\n", (uint64_t)eprocess_ptr->CommitCharge * 4); } tick-30s { exit(0); } // Requires symbols: Set _NT_SYMBOL_PATH environment variable // Run with: dtrace -s process_working_set.d ``` -------------------------------- ### Generate ETW Events from DTrace Script (D) Source: https://context7.com/microsoft/dtrace-on-windows/llms.txt Illustrates how to emit custom ETW (Event Tracing for Windows) events from a DTrace script on Windows. This script specifically monitors for failed system calls and generates warning-level ETW events containing process information and the status code. ```d // D Script: emit_etw_events.d // This script monitors failed syscalls and emits custom ETW events syscall:::return / (uint32_t)arg0 == 0xc0000001UL / /* STATUS_UNSUCCESSFUL */ { etw_trace( "Tools.DTrace.Platform", /* Provider Name */ "AAD330CC-4BB9-588A-B252-08276853AF02", /* Provider GUID */ "FailedSyscall", /* Event Name */ 3, /* Level: Warning */ 0x0000000000000001, /* Keyword */ "etw_int32", "ProcessID", (int32_t)pid, "etw_string", "ProcessName", execname, "etw_string", "Function", probefunc, "etw_int32", "Status", (int32_t)arg0 ); } // Run with: dtrace -s emit_etw_events.d // View with: Windows Performance Analyzer or tracelog.exe ``` -------------------------------- ### DTrace - Timer Set/Cancel Summary Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/README.md This DTrace script summarizes timer set and cancel operations for a duration of 3 seconds. It focuses on probes related to timer functions (Nt*Timer*) and captures counts based on probe function, executable name, and PID. Requires DTrace framework. ```dtrace dtrace -Fn "tick-3sec { exit(0);} syscall::Nt*Timer*:entry { @[probefunc, execname, pid] = count();}" ``` -------------------------------- ### Managing UCPP Lexer State Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/lib/ucpp/README.md Memory associated with the lexer state can be released using 'free_lexer_state()'. To reset tables like macros and assertions, call 'init_cpp()'. The 'wipeout()' function releases most dynamically allocated memory, returning ucpp to its initial state. ```c free_lexer_state(); init_cpp(); wipeout(); ``` -------------------------------- ### Undefined Behavior with 'defined' Operator and Macro Expansion Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/lib/ucpp/README.md Illustrates a tricky case with the 'defined' operator and macro expansion using '##'. Ucpp's behavior differs from some other preprocessors, leading to an open question about standard compliance. ```c #define undefined ! #define makeun(x) un ## x #if makeun(defined foo) qux #else bar #endif ``` -------------------------------- ### DTrace - Dump System Process Structure Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/README.md This DTrace script dumps the kernel structure of the system process (nt`_EPROCESS`). It requires the symbol path to be correctly configured for local symbol caching to resolve kernel structures. The script prints the process information and exits. ```dtrace dtrace -n "BEGIN{print(*(struct nt`_EPROCESS *) nt`PsInitialSystemProcess);exit(0);}" ``` -------------------------------- ### Configuring UCPP Identifier Characters Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/lib/ucpp/README.md The 'set_identifier_char()' and 'unset_identifier_char()' functions allow runtime configuration of characters considered part of identifiers. This affects identifier tokenizing but not numeric constants. Calling 'init_cpp()' restores the default identifier character set. ```c set_identifier_char('$'); // ... later ... unset_identifier_char('$'); // To restore defaults: init_cpp(); ``` -------------------------------- ### UCPP Preprocessor Mode Operations Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/lib/ucpp/README.md In non-lexer mode, the 'cpp()' function is used to analyze tokens. It returns a positive value on error. For both modes, 'check_cpp_errors()' should be called after end-of-file detection for pending errors, and 'flush_output()' is used in non-lexer mode. ```c int result = cpp(); if (result > 0) { // Genuine error } // After end of file: check_cpp_errors(); if (non_lexer_mode) { flush_output(); } ``` -------------------------------- ### Macro-Replaced Pragma Directive Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/lib/ucpp/README.md Defines macros to enable macro-replaced pragmas, useful for dynamic pragma inclusion. Note that pragmas do not nest. ```c #define pragma_(x) _Pragma(#x) #define pragma(x) pragma_(x) ``` -------------------------------- ### UCPP Lexer Mode Operations Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/lib/ucpp/README.md In lexer mode, the 'lex()' function is called repeatedly to process tokens. It returns a non-zero value on error and CPPERR_EOF upon reaching the end of input. Whitespace tokens are skipped. Memory for token string values is managed automatically, requiring explicit copying if retention is needed. ```c int result = lex(); if (result == CPPERR_EOF) { // End of input reached } else if (result != 0) { // Genuine error, skip token and call lex() again // ls->ctok is an undefined token lex(); } ``` -------------------------------- ### Ambiguous Macro Concatenation Behavior Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/lib/ucpp/README.md Demonstrates a scenario with nested macros and the '##' operator where the C standard is unclear about the expected output. Ucpp's behavior is discussed in relation to historical committee discussions. ```c #define CAT(a, b) CAT_(a, b) #define CAT_(a, b) a ## b #define AB(x, y) CAT(x, y) CAT(A, B)(X, Y) ``` -------------------------------- ### _Pragma Operator Evaluation Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/lib/ucpp/README.md Explains the evaluation of the _Pragma operator in ucpp, which is treated as a special macro with lazy replacement. It can be evaluated within directives, but this behavior can be controlled. ```c /* Ucpp evaluates _Pragma lazily. */ /* Behavior can be controlled by defining NO_PRAGMA_IN_DIRECTIVE. */ ``` -------------------------------- ### UCPP COPY_LINE Buffer Usage Source: https://github.com/microsoft/dtrace-on-windows/blob/windows/lib/ucpp/README.md When the COPY_LINE flag is enabled, read lines are stored in 'copy_line[]' up to 'COPY_LINE_LENGTH - 1' characters. This buffer is used for error reporting. If an error occurs, 'ls.copy_line[ls.cli] = 0;' can be used to ensure null termination if the line was not fully read. ```c if (ls.cli != 0) { ls.copy_line[ls.cli] = 0; } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.