Yesterday I asked a question about the behavior of windbg aliases (Strange behavior of windbg alias in loops) and got some helpful answers.
Now I have a simplified example that shows the behavior I am seeing, without any loops. It seems like alias replacement is simply broken, and the documentation about .block {} is basically wrong.
In a foo.windbg script I have the following:
;aS ${/v:foo} 1
al
.block
{
.echo foo
}
I run the script with
$$><foo.windbg
If the alias foo is not defined before running the script (or if it is already defined to 1), this works as expected. However if I already have foo defined to a different value, e.g. 0
;aS ${/v:foo} 0
then when I run the script foo gets set to 1 (I can see that from the al command in the script) but the command .echo foo in the script produces 0. Even the reference to foo is in a .block{}.
It works if the closing curly brace in the block statement is immediately after the reference to foo
;aS ${/v:foo} 1
al
.block
{
.echo foo}
This doesn't help because it means you can't use the alias unless it happens to be at the end of a .block{} or other compound statement. I though referencing the alias with ${foo} would help but it does not.
From the answers to my previous question I see that deleting (ad) the alias before setting it seems to fix the problem in some cases. Just using
ad foo
will error out the script if foo is not defined so I can't use it. Using
ad *
works but deletes all aliases including ones I have already created and want to use. I tried
.if (${/d:foo}) {ad ${/v:foo}}
but that gives the same behavior, where foo is replaced with the old value when used further down in the script. So I guess the work-around is to start the script with
aS ${/v:foo} dummy
ad ${/v:foo}
which seems to work.
So the basic problem is that alias replacement fails (in some cases) unless the alias name is followed by the closing curly brace of certain statements like .block. All the examples from the windbg documentation just so happen to do exactly this, and/or delete all aliases first and work around the problem that way.
I know I'm beating the dead horse but does this behavior have an explanation? Am I confused? It seems simply broken and, for the way I want to use aliases, useless.
Thanks,
Dave
It seems you have many questions. It's about deleting aliases, using aliases, running scripts, understanding WinDbg ...
Deleting aliases
One of them is "How to delete an alias without knowing in advance whether it's defined or not?" The answer to that is .block{ad /q ${/v:foo}}.
How to use aliases in your scripts
The next thing I'd advise for is: do not use aliases without the alias syntax. This is not so much for WinDbg itself, but rather for the readers of your script and for maintainability.
When I see a line
.echo foo
then I expect it to print "foo" and nothing else. When I see a line
.echo ${foo}
then I know that there is a variable or alias involved.
Conceptual bug with aliases: unable to escape them
Actually I think this is a conceptual bug, because there's no reliable way in WinDbg to echo a literal "foo", but in most echo scenarios I just want it to do that and nothing else
0:000> as foo oops
0:000> .echo foo
oops
0:000> .echo "foo"
oops
0:000> .echo ${foo}
oops
0:000> .echo "${foo}"
oops
0:000> .echo ${/v:foo}
${/v:foo}
0:000> .echo "${/v:foo}"
${/v:foo}
0:000> .printf "foo"
oops
0:000> .printf "${foo}"
oops
0:000> .printf "${/v:foo}"
${/v:foo}
And then you find bugs like you do:
0:000> .printf "foo\n"
foo
Your use of aliases
I appreciate that you provide small MREs to reproduce your issues. From what I see it looks like you're trying to use aliases like variables.
Let's think about what an alias is: You use aliases on Linux if you have a command that you need often but it's too long or complicated to type. I have aliases defined like ll for ls -l and cd.. for cd .. because I'm somewhat used to the Windows syntax.
The problem is: a WinDbg alias is not an alias as you know it from Linux. It's more like a preprocessor definition doing a stupid search and replace.
In the cases you presented so far, it has nothing to do with having an abbreviation for shorter typing or circumventing typing mistakes. You seem to assign it a value. In that case you should consider using pseudo registers like $t1.
Running scripts
You are running the script with $$>< and that method has the property of
Condenses to single command block: Yes
What it will do: it concatenates all lines in the file by a semicolon. Any you have to live with the consequences of that. See "further reading" on how that causes problems.
Further reading
It seems you want to understand WinDbg. That post will make you scratch your head and facepalm. What you'll learn there:
You can't simply concatenate commands using ; as a separator
You can't simply write empty statements
WinDbg is whitespace sensitive (sometimes)
A line is not always a line
String escaping is broken
Comments are not always comments
But why?
Warning: pure speculation ahead. I have never worked for Microsoft.
Why is that? WinDbg exists for an incredibly long time. The oldest version I have on my computer is version 4.0.18 from 1999, likely developed for Windows NT 4 SP 6. I can imagine that WinDbg 3 versions for Windows NT 3 existed as well, so it potentiall goes back to 1993.
At that time, there were no IDE features like "Find references" or "Find usages", so it was quite hard to do an impact analysis and I believe it was often unclear to developers what side effects a new command like as could have.
Combined with the impression of WinDbg being a Microsoft internal tool only and "the developers will know what they are doing" gives us a useful but overall buggy tool today.
WinDbg was probably not developed with a clear roadmap in mind. It probably does not have something you'd call "architecture". Some developer was debugging something complicated and thought it would be great to provide a sort of script to others in order to make debugging easier. So WinDbg is likely more a collection of useful code snippets we call commands today, but they have no common lexer or parser, for example.
i don't see a solid use case in the query so i wont go into the alias debate ;
also the query is a bit of an xy problem because you think using alias is the way out for your contrived problem instead of talking about what the actual problem you are trying to solve .
but if you want some modern UserVariables try checking out Javascript you can probably pull what you want out to a standard es6 compliant framework
0:000> dx Debugger.State.UserVariables
Debugger.State.UserVariables
0:000> dx #$foo = "sugar"
#$foo = "sugar" : sugar
Length : 0x5
0:000> dx #$blah = "honey"
#$blah = "honey" : honey
Length : 0x5
0:000> dx -r0 "i want "+ #$foo+ " mixed With "+#$blah
"i want "+ #$foo+" mixed With "+#$blah : i want sugar mixed With honey
just to complete the loop here is a javascript that compares a user provided argument with an already existing UserVariable and does some debugprinting
"use strict";
function foo(argu)
{
for (var i in host.namespace.Debugger.State.UserVariables)
{
if(i===argu)
{
host.diagnostics.debugLog("hi " + i +" with me ");
var tmp = "host.namespace.Debugger.State.UserVariables." + i
var boo = eval(tmp)
host.diagnostics.debugLog(boo +"\n")
}
}
}
create few user variables with
dx #$foo = "sugar"
dx #$bar = "honey"
dx #$blah = "milk"
0:000> dx Debugger.State.UserVariables
Debugger.State.UserVariables
foo : sugar
bar : honey
blah : milk
load the script and play with it
0:000> .scriptload d:\test.js
JavaScript script successfully loaded from 'd:\test.js'
0:000> dx #$scriptContents.foo("bar")
hi bar with me honey
#$scriptContents.foo("bar")
0:000> dx #$scriptContents.foo("foo")
hi foo with me sugar
#$scriptContents.foo("foo")
0:000> dx #$scriptContents.foo("blah")
hi blah with me milk
#$scriptContents.foo("blah")
Related
I've found some Perl code that makes the following check:
if ($^O eq 'MSWin32')
What is the $^0 variable? It looks like it contains the architecture/OS of the machine it's running on, but I don't know if that's the result of assigning it elsewhere in the script (maybe it's the result of a regex match, though I can't see any match operations performed before that point), or whether that variable always has a value related to the machine it's running on.
I'd like to check the OS and bitness of the machine running the script, and would like to know if I can use $^0 to help me with that (if not, then I'm still curious what it is).
I'd rather not publish other parts of the Perl script, as it's proprietary.
This strikes me as the sort of question that should have been asked before, but Google isn't much use, thanks to the special characters (I often think the inability to Google Perl code led in part to its demise), and Stack Overflow doesn't have any useful suggested questions either.
There's no match for $^0 or $^1 or $^# on the perlvar page, and I'm not convinced that $^N or $^X are related.
It is not a zero.
It is the letter "O", capitalized.
In perlvar, search for OSNAME, which is the long form name of the variable when you use English:
The name of the operating system under which this copy of Perl was
built, as determined during the configuration process.
There is no special "dollar caret zero" variable.
I would like to turn a led (character device) of an embedded linux board (BeagleBone Black) on and off with a script written in D.
Via the command line a led can be turned on and off (e.g. for led "USER LEDS D2 0") with:
cd /sys/class/leds/beaglebone:green:usr0
echo none > trigger
echo 1 > brightness
echo 0 > brightness
(echo none > trigger disables the default "heartbeat" flashing)
In the D Cookbook on page 93 I found info about how to make linux system calls via the C interface like follows:
void main(){
import core.sys.posix.unistd; // analogous to #include <unistd.h>
string hello = "Hello, world!";
write(1 /*stdout file descriptor*/, hello.ptr, hello.length);
}
Is that a suitable way to access a character device or are there better alternatives?
The unistd calls are indeed the correct way to do it. A character device in Linux is a special kind of file and is accessed the same way: you open it by path, then read or write to it, and close it when finished.
Note that open is actually inside core.sys.posix.fcntl, while read is in core.sys.posix.unistd.
You could also use std.file.write() from the D standard library to be a bit shorter. There's also chdir in there. So your shell example would literally become:
import std.file;
chdir("/sys/class/leds/beaglebone:green:usr0");
std.file.write("trigger", "none"); // write "filename", "data string"
std.file.write("brightness", "1");
std.file.write("brightness", "0");
You don't strictly have to use std.file.write as the full name with the import, I just like to since write is such a common word it clears up which one we mean.
Anyway, this function just wraps up the unistd calls for you: it opens, writes the string, and closes all in one (just like the shell echo!).
One small difference is shell echo sticks a \n at the end of the string. I didn't do that here. If the code doesn't work, try "1\n" and such instead, maybe the device requires that. But I doubt it.
But the std.file.write vs the core.sys.posix.unistd.write aren't that much different. The former is more convenient, the latter gives more precise control over it.
In WinDbg, I can get the callstack using the k command. For DLLs without symbols, it displays an incorrect method name and a large offset, e.g.
0018f9f0 77641148 syncSourceDll_x86!CreateTimerSyncBridge+0xc76a
Since I don't have symbols, I have to give this information to the developer of the DLL. I don't know who will work on the bug and how much debugging knowledge he has. I want to avoid that the developer thinks the problem is in the CreateTimerSyncBridge() method.
Is there a way to get the callstack without method names, just with offsets?
At the moment I'm using the following workaround:
0:000> ? syncSourceDll_x86!CreateTimerSyncBridge+0xc76a
Evaluate expression: 1834469050 = 6d57c6ba
0:000> ? syncSourceDll_x86
Evaluate expression: 1834287104 = 6d550000
0:000> ? 6d57c6ba-6d550000
Evaluate expression: 181946 = 0002c6ba
So I can modify the callstack manually to
0018f9f0 77641148 syncSourceDll_x86!+0x2c6ba
But that's really hard to do for a lot of frames in a lot of threads.
You can specify that the symbols must match exactly using a stricter evaluation, either by starting windbg with command line parameter -ses or issuing the command:
.symopt +0x400
The default is false for the debugger, if you wish to reset this then just remove the option:
.symopt -0x400
See the msdn docs: https://msdn.microsoft.com/en-us/library/windows/hardware/ff558827(v=vs.85).aspx#symopt_exact_symbols
I'm running the debugger in noninteractive mode, with the output written to a file. I want to print out each line of my Perl script as it executes, but only lines in the script itself. I don't want to see the library code (File::Basename, Exporter::import, etc.) that the script calls. This seems like the sort of thing that should be easy to do, but the documentation for perldebug only discusses limiting the depth for dumping structures. Is what I want possible, and if so, how?
Note that I'm executing my program as follows:
PERLDB_OPTS="LineInfo=temp.txt NonStop=1 AutoTrace=1 frame=2" perl -dS myprog.pl arg0 arg1
By default, Devel::DumpTrace doesn't step into system modules, and you can exercise fine control over what modules the debugger will step into (it's not easy, but it's possible). Something like
DUMPTRACE_FH=temp.txt perl -d:DumpTrace=quiet myprog.pl
would be similar to what you're apparently trying to do.
Devel::DumpTrace also does a lot more processing on each line -- figuring out variable values and including them in the output -- so it may be overkill and run a lot slower than perl -dS ...
(Crikey, that's now two plugs for Devel::DumpTrace this week!)
Are you talking about not wanting to step through functions outside of your own program? For that, you want to use n instead of s.
From perldebug:
s [expr] Single step. Executes until the beginning of another
statement, descending into subroutine calls. If an
expression is supplied that includes function calls, it too
will be singleāstepped.
n [expr] Next. Executes over subroutine calls, until the beginning
of the next statement. If an expression is supplied that
includes function calls, those functions will be executed
with stops before each statement.
I wish to do
lua prog.lua arg1 arg2
from the command line
Inside prog.lua, I want to say, for instance
print (arg1, arg2, '\n')
Lua doesn't seem to have argv[1] etc and the methods I've seen for dealing with command line arguments seem to be immature and / or cumbersome. Am I missing something?
You're missing the arg vector, which has the elements you want in arg[1], arg[2], and so on:
% lua -i -- /dev/null one two three
Lua 5.1.3 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> print(arg[2])
two
>
More info in the Lua manual section on Lua standalone (thanks Miles!).
In addition to the arg table, ... contains the arguments (arg[1] and up) used to invoke the script.
% lua -i -- /dev/null one two three
Lua 5.1.3 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> print(...)
one two three
Lua stores arguments in a table. This table is the "arg" table. You can access the passed arguments inside using arg[1], arg[2], ...
arg[0] is the name of the lua program. arg[1] is the first argument passed, arg[2] is the second argument passed and so on...
If you run file.lua in cmd of freeswitch
freeswitch> luarun prog.lua arg1
You can use prog.lua:
#print(argv[1])
And run: $lua prog.lua arg1 (run in script folder)
You can use prong.lua:
#print(arg[1])
For OP and future visitors,
The library of Lua doesn't contain injecting a table 'args' into globals from command line switches. The program built from lua.c does, however, it is near impossible to use. The reason it is impossible to use is that program does NOT like multiple switches.
This is one of the reasons why my REPL/code executor LuaConsole was built. It gives you the table args as well as sends a tuple to the root pcall function (your executing environment is really a top-level pcall with probably an error handler attached). So both args[n] and local a = {...}; a[n] ...; all work properly with as many switches as you want. For example, -e to execute code from cmd line, -l to specify libraries, etc. It supports anything lua51 and up.
If you are having troubles with the program in the library, I highly suggest you check out https://www.github.com/tilkinsc/LuaConsole as it will save you the headache of dealing with a broken-feeling program. There are also other alternatives out there such as for web, fengari.
Hope this helps you!