Why am I getting a Invalid parameter poi(adr+4) when I run the following command in WinDbg while debugging a dump file?
.foreach ( adr { !dumpheap -mt 66df13d4 -short } ) { !do poi(adr+4); }
The following shows that the value of adr is getting populated just fine.
.foreach ( adr { !dumpheap -mt 66df13d4 -short } ) { .echo adr; }
I want to get the contents of a .NET string variable that is stored at the 4th offset of a System.Web.Caching.CacheEntry object.
You need to have spaces around adr or use ${adr}. This is documented in MSDN
Note When the string Variable appears within OutCommands, it must be
surrounded by spaces. If it is adjacent to any other text -- even a
parenthesis -- it will not be replaced by the current token value,
unless you use the ${ } (Alias Interpreter) token.
Related
Ciao all -
I'm using Powershell 7.2 to automate some hardware configuration through the hardware's CLI.
I am using a loop to generate strings that include "0x" prefixes to express hex bytes, but having an issue where any consecutive iterations after the first pass of the loop do not print the "0x" prefix.
The following will produce the issue:
function fTest($id)
{
foreach($n in #(1, 2, 3))
{
write-host $id.gettype()
write-host ("{0:x}" -f $id)
$id++
}
}
fTest 0x1a
Actual output:
System.Int32
0x1a
System.Int32
1b
System.Int32
1c
The 0xprefixes are omitted in iters 2 and 3.
Why is this happening?
What is a clean way to correct the issue?
I'm a PowerShell noob, so I am happy to receive suggestions or examples of entirely different approaches.
Thanks in advance for the help!
tl;dr
Type-constrain your $p parameter to unambiguously make it a number (integer), as Theo suggests:
function fTest($id) -> function fTest([int] $id)
Build the 0x prefix into the format string passed to -f:
"{0:x}" -f $id -> '0x{0:x}' -f $id
Building on the helpful comments:
Why is this happening?
Format string {0:x}, when applied to a number, only ever produces a hexadecimal representation without a 0x prefix; e.g.:
PS> '{0:x}' -f 10
a # NOT '0xa'
If the operand is not a number, the numeric :x specification is ignored:
PS> '{0:x}' -f 'foo'
foo
The problem in your case is related to how PowerShell handles arguments passed to parameters that are not type-constrained:
Argument 0x1a is ambiguous: it could be a number - expressed as hexadecimal constant 0x1a, equivalent to decimal 26 - or a string.
While in expression-parsing mode this ambiguity would not arise (strings must be quoted there), it does in argument-parsing mode, where quoting around strings is optional (except if the string contains metacharacters) - see the conceptual about_Parsing topic.
What PowerShell does in this case is to create a hybrid argument value: The value is parsed as a number, but it caches its original string representation behind the scenes, which is used for display formatting, for instance:
PS> & { param($p) $p; $p.ToString() } 0x1a
0x1a # With default output formatting, the original string form is used.
26 # $p is an [int], so .ToString() yields its decimal representation
As of PowerShell 7.2.2, surprisingly and problematically, in the context of -f, the string-formatting operator, such a hybrid value is treated as a string, even though it self-reports as a number:
PS> & { param($p) $p.GetType().FullName; '{0:N2}' -f $p } 0x1a
System.Int32 # $p is of type [int] == System.Int32
0x1a # !! With -f $p is unexpectedly treated *as a string*,
# !! yielding the cached original string representation.
This unexpected behavior has been reported in GitHub issue #17199.
Type-constraining the parameter to which such a hybrid argument is passed, as shown at the top, avoids the ambiguity: on invocation, the argument is converted to an unwrapped instance of the parameter's type (see next point).
As for why the output changed starting with the 2nd iteration:
The cached string representation is implemented by way of an invisible [psobject] wrapper around the instance of the numeric type stored in $id, in this case.
When you update this value by way of an increment operation (++), the [psobject] wrapper is lost, and the variable is updated with an unwrapped number (the original value + 1).
Therefore, starting with the 2nd iteration, $id contained an unwrapped [int] instance, resulting in the {0:x} number format being honored and therefore yielding a hexadecimal representation without a 0x prefix.
The only reason the 1st iteration yielded a 0x prefix was that it was present in the original string representation of the argument; as stated above, the numeric :x format specifier was ignored in this case, given that the -f operand was (unexpectedly) treated as a string.
I'm using a format operator inside a script with a following example:
$current = 1
$total = 1250
$userCN = "contoso.com/CONTOSO/Users/Adam Smith"
"{0, -35}: {1}" -f "SUCCESS: Updated user $current/$total", $userCN
This excpectedly shows the following output:
SUCCESS: Updated user 1/1250 : contoso.com/CONTOSO/Users/Adam Smith
The format operator is there to keep the targeted output text in place with current / total running numbers varying between 1-99999. Without the format operator I could highlight the success line like this:
Write-Host -BackgroundColor Black -ForegroundColor Green "SUCCESS: Updated user $current/$total: $userCN"
But the question is how could I use the highlight-colors combined with the format operator? There's only the -f parameter and it doesn't allow the color parameters because, well, it's not the same thing as Write-Host in the first place.
Unlike other shells, PowerShell allows you to pass commands and expressions as command arguments simply by enclosing them in parentheses, i.e by using (...), the grouping operator.
When calling PowerShell commands (cmdlets, scripts, functions), the output is passed as-is as an argument, as its original output type.
Therefore, Theo's solution from a comment is correct:
Write-Host -BackgroundColor Black -ForegroundColor Green `
("{0, -35}: {1}" -f "SUCCESS: Updated user $current/$total", $userCN)
That is, the -f expression inside (...) is executed and its output - a single string in this case - is passed as a positional argument to Write-Host (implicitly binds to the -Object parameter).
Note that you do not need, $(...), the subexpression operator, in this case:
(...) is sufficient to enclose an expression or command.
In fact, in certain cases $(...) can inadvertently modify your argument, because it acts like the pipeline; that is, it enumerates and rebuilds array expressions as regular PowerShell arrays (potentially losing strong typing) and unwraps single-element arrays:
# Pass a single-element array to a script block (which acts like a function).
# (...) preserves the array as-is.
PS> & { param($array) $array.GetType().Name } -array ([array] 1)
Object[] # OK - single-element array was passed as-is
# $(...) unwraps it.
PS> & { param($array) $array.GetType().Name } -array $([array] 1)
Int32 # !! Single-element array was unwrapped.
# Strongly-typed array example:
PS> & { param($array) $array.GetType().Name } ([int[]] (1..10))
Int32[] # OK - strongly typed array was passed as-is.
# Strongly-typed array example:
PS> & { param($array) $array.GetType().Name } $([int[]] (1..10))
Object[] # !! Array was *enumerated and *rebuilt* as regular PowerShell array.
The primary use of $(...) is:
expanding the output from expressions or commands inside expandable strings (string interpolation)
To send the output from compound statements such as foreach (...) { ... } and if (...) { ... } or multiple statements directly through the pipeline, after collecting the output up front (which (...) does as well); however, you can alternatively wrap such statements & { ... } (or . { ... } in order to execute directly in the caller's scope rather than a child scope) in order to get the usual streaming behavior (one-by-one passing of output) in the pipeline.
Taking a step back: Given that you already can use compound statements as expressions in variable assignments - e.g., $evenNums = foreach ($num in 1..3) { $num * 2 } - and expressions generally are accepted as the first segment of a pipeline - e.g., 'hi' | Write-Host -Fore Yellow - it is surprising that that currently doesn't work with compound statements; this GitHub issue asks if this limitation can be lifted.
In the context of passing arguments to commands:
Use $(...), the subexpression operator only if you want to pass the output from multiple commands or (one or more) compound statements as an argument and/or, if the output happens to be a single object, you want that object to be used as-is or, if it happens to be a single-element array (enumerable), you want it to be unwrapped (pass the element itself, not the array.
Of course, if you're constructing a string argument, $(...) can be useful inside that string, for string interpolation - e.g., Write-Host "1 + 1 = $(1 + 1)"
Use #(...), the array subexpression operator only if you want to pass the output from multiple commands as an argument and/or you want to ensure that the output becomes a array; that is, the output is returned as a (regular PowerShell) array, of type [object[]], even if it happens to comprise just one object. In a manner of speaking it is the inverse of $(...)'s behavior in the single-object output case: it ensures that single-object output too becomes an array.
A part of my bison grammar is as shown
head: OPEN statement CLOSE
{
$$=$2;
}
;
statement: word
{
$$=$1;
}
| statement word
{
$$=$1;
printf("%s",$$);
}
;
Now if my input is [hai hello] where [ is the OPEN & ] is the CLOSE respectively,then in the printf statement I get the output as "hai hello" itself..but in the $$ of head I get "hai hello]". Same happens with other grammars too.i.e., if i try to print valye of $1,the values of $2,$3,... are also printed.. why is it so.
The problem is probably in your lexer -- you probably have lexer actions that do something like yylval.str = yytext; to return a semantic value. The problem is that yytext is a pointer into the scanner's read buffer and is only valid until the next call to yylex. So all your semantic values in the parser quickly become dangling pointers and what they point at is no longer valid.
You need to make a copy of the token string in the lexer. Use an action something like yylval.str = strdup(yytext);. Of course, then you have potential memory leak issues in your parser -- you need to free the $n values you don't need anymore.
I have an array of Relative Virtual Addresses (RVAs) located at a particular memory address. I can dump it in windbg and see the list of RVAs as show below:
dd 77f10000+00002650 and
output is:
77f12650 000034a6 000034af 000034b9 000034ce
....
Here, 77f10000 is the base address of the DLL and 00002650 is the RVA of the array which I have displayed.
Now, each of these RVA's in the memory dump can be added to the base address of the DLL and the corrresponding string at the location can be viewed.
For instance, if I take the first entry in the array which is: 000034a6
By adding this RVA to the base address of DLL, 77f10000 and displaying it as follows:
da 77f10000+000034a6 and
output is: 77f134a6 "AbortDoc"
now, this way, I can view the next string for the next corresponding RVA in the array by doing the following:
da 77f10000+000034af and
output is: 77f134af "AbortPath"
Similarly I want to iterate over the remaining entries in the array and display the corresponding strings.
I want to do this using a one liner script in windbg. I want to learn how to do this however I could not find enough documentation or examples around on the net which would help me craft something similar.
I think the, .foreach command can be used to do this:
Example: .foreach(myVariable {dd 77f10000+00002650}){!do }
myVariable is going to store the output of the windbg command. However, I need to pick one element at a time from the line and iterate.
Any help would be appreciated.
Thanks.
It's unfortunately harder than it should be because the dd command displays not only the result but the address of the result, so .foreach is going to iterate over both. While I couldn't do it in one line, I did it in a script file that only looks long because of the comments:
$$ Set up the base of the RVA array as a pointer to an integer.
r? #$t0 = ((int *)(0x8068f764))
$$ To break down the command:
$$ r? - Allows you to assign a pseudo register and give it a type
$$ #$t0 - Pseudo register for use in scripting
$$ ((int *)(address) - Assign the type int * to the result
$$ Loop over the entries in the array, 100 is arbitrary and should be replaced
.for (r #$t1 = 0; #$t1 < 100; r #$t1 = #$t1 + 1)
{
$$ Display the ASCII string at the given offset. This is similar to:
$$
$$ printf("%s\n", baseAddr+(offsetArray[i])
$$
$$ ##c++() is required so that #$t0 is treated as an int *
da nt+(##c++(#$t0[#$t1]));
}
Save to a TXT file and run with the following command:
0: kd> $$><c:\dumps\dumprvas.txt
80691a4b "CcCanIWrite"
80691a57 "CcCopyRead"
80691a62 "CcCopyWrite"
80691a6e "CcDeferWrite"
80691a7b "CcFastCopyRead"
80691a8a "CcFastCopyWrite"
...
If I were doing this for real I'd clean that up even more and make the base address and entry count parameters to the script, which would make it more useful. I left it out here though for clarity (well, as much clarity as can be expected with these scripts :)).
-scott
very late answer but here is a oneliner as requested :)
0:000> .foreach /ps 1 /pS 1 (place { dd /c 1 gdi32+2650 l?5 }) {da gdi32 + place }
test output
0:000> .foreach /ps 1 /pS 1 (place { dd /c 1 gdi32+2650 l?5 }) {da gdi32 + place }
77f134a6 "AbortDoc"
77f134af "AbortPath"
77f134b9 "AddFontMemResourceEx"
77f134ce "AddFontResourceA"
77f134df "AddFontResourceExA"
I want to create an LLDB alias ps, such that
ps foo
becomes
print [self foo]
I've been watching the LLDB talk (WWDC session 321 on iTunes), and based on that, it looks like the alias to do that should be this one:
command alias ps print [ self %1 ]
but it doesn't work. Here I've given my app delegate a simple "count" method that returns an integer:
(lldb) command alias ps print [ self %1 ]
(lldb) ps count
error: invalid operands to binary expression ('AppDelegate *' and 'int')
error: 1 errors parsing expression
(lldb) print [ self count ]
(int) $6 = 2
(lldb)
What am I missing?
It seems arguments (%1, %2, etc) doesn't work to alias an expression. There is a workaround by using a regular expression instead:
command regex ps 's/(.+)/print [self %1]/'
It makes an alias ps for the above regular expression:
(lldb) ps firstName
print [self firstName]
(NSString *) $1 = 0x06e64e20 #"John"
However this will last till the debug session ends. You'll have to enter it again for the next debug session. If you want your ps command to persist through debug sessions, you'll have to save it in your ~/.lldbinit file (if it doesn't exist, create one).
See llvm blog for more deails about regex command.