Since a few friends complained about adding me to their RSS feed, then not actually posting anything I thought I'd post a little something about some of the recent hacks I've been up to.
See the extended version for details on
/path/to/application [0xAAAAAA] << address of codewhich initially seemed a bit cryptic, but by putting it together with
/path/to/application [0xAAAAAA] << address of code
/path/to/application [0xAAAAAA] << address of code
/path/to/application [0xAAAAAA] << address of code
static void print_trace()of course you need to use a few C externs to make this work:
{
void *btarray[10];
size_t size;
char **strings;
size_t i;
pid_t pid = getpid();
//writefln("SEG");
size = backtrace(cast(void**)btarray, 10);
strings = backtrace_symbols(cast(void**)btarray, size);
std.process.system("/bin/echo '----BACKTRACE------' " ~
"> /var/log/myproject/backtrace.log");
for(i = 0; i < size; i++) {
char[] line = std.string.toString(strings[i]);
char[][] bits = std.string.split(line, "[");
char[] left = std.string.strip(bits[0]);
if (!left.length) {
continue;
}
// skip lines with ( in them...
if (std.string.find(left,"(") > -1) {
continue;
}
char[] addr = bits[1][2..length-1];
std.process.system("/bin/echo '----" ~ addr
~ "------' >> /var/log/myproject/backtrace.log");
std.process.system("/usr/bin/addr2line -f -e " ~
left ~ " " ~ addr ~ " >> /var/log/myproject/myproject.log");
}
free(strings);
}
extern (C) {and to add it to you application, stick this in main() somewhere
int backtrace(void **__array, int __size);
char** backtrace_symbols(void **__array, int __size);
pid_t getpid();
sighandler_t signal(int signum, sighandler_t handler);
void sigsegv(int sig)
{
// reset the handler.
signal(SIGSEGV, cast(sighandler_t) 0);
print_trace();
// really die
exit(SIGSEGV);
}
}
signal(SIGSEGV, &sigsegv);testing it is quite simple, just do this in D
void testSegfault()Now looking at the debug file, you can work out where it failed...
{
class SegTest {
void test() {}
}
SegTest a;
a.test();
}
----BACKTRACE------I'm sure with some more work, you could get it to log to syslog...
----805e971------ (THIS IS MY OUTPUT CODE)
_D9myproject7cmdLine6daemon11print_traceFZv
init.c/src/myproject/cmdLine/daemon.d:306
----805e46b------
sigsegv
init.c/src/myproject/cmdLine/daemon.d:121
----804db18------ (AND NOW FOR THE LOCATION OF THE SEGFAULT)
_D9myprojectfort7manager7manager7runOptsFZAa
init.c/src/myproject/manager.d:50
----805617a------
_D9myproject10webRequest10webRequest5parseFAaAaKAaZAa
init.c/src/myproject/webRequest.d:89
----8050c3e------
_D9pmyproject14myprojectThread14myprojectThread18dealWithWebRequestFAaAaZv
init.c/src/myproject/myprojectThread.d:331
----80503d0------
_D9myproject14myprojectThread14myprojectThread3runFZi
init.c/src/myproject/myprojectThread.d:111
----8076260------
_D3std6thread6Thread11threadstartUPvZPv
??:0
----a7fd10bd------
??
I've been spending far to much time looking at the autocompletion in leds for D. The justification, while growing weaker the more time i spend on it, remains the same. Autocompletion and AutoHelp save a huge amount of time when writing code.
The PHP parser in leds is working quite well, is organically written, and has room to grow, the next major step is guessing object types by matching method calls on unknown objects, so while I spend about the same amount of time coding in D as I do in PHP now, I had decided to look at the D parser, and push that along.
Antonio had written the current parser which is in the dantfw project. It aimed to parse all C like languages, C, D, Java and C# etc. This meant that rather than following the D specification, the tokenizer and parser where quite generic. and lead to two issues.
The first issue I resolved by rewriteing the tokenizer (following the D specification closely), and re-tokenizing the document as you type (if it thinks your scope may have changed), then deducing the scope being input.
The second, I began to conclude was more related to the generic nature of the parser. It was making many assuptions about the language that turned out to be incorrect in D's context. The only, rather drastic solution was to rewrite the parser....
So on rather a quiet day i started that thankless task. Using Antonio's original design, of using object contructors to parse and eat their own tokens, I set about writing loads of switch/case combos.
My first effort worked reasonably well, but the more i wrote it, I began to realize that both the complexity, and the use of a series of tokens had a number of flaws. The declaration code for parsing methods, and variables was quite large, and very similar. (ending in a lot of redundant, duplicate code) Declaring multiple variables in one line also made the resulting abstract syntax tree objects quite klunky.
At this point I put it on hold for a while, partly to consider alternative approaches, and more to ensure paid work was not falling behind.
When i returned, I had come up with a few ideas
void main(char[][] argv) { }Which would tokenize into the following.
Token.T_void : void
Token.IDENTIFIER main
'('
Token.T_char char;
'['
']'
'['
']'
Token.IDENTIFIER argv
')'
'{'
'}'
Token.T_void : voidFrom a pattern perspective, we are just looking for
Token.IDENTIFIER main
'('
Token.T_char char;
'['
']'
'['
']'
Token.IDENTIFIER argv
')'
'{'
'}'
BaseType, IDENTIFIER '(' '{' == a method declaration.(although it's a bit more complex than that in real life!)
/* See original for copyright - I've removed for the example) */Click on the more bit for the full story..
// give this file a module name (bit like namespaces)
module hw.HelloWorld;
// private imports so that any code importing this,
// doesnt import these as well.
// so you dont flood the global namespace too much..
private import dui.MainWindow;
private import dui.DUI;
public:
class HelloWorld : MainWindow // it extends MainWindow..
{
private import dui.Label; // imports can go here as well..
char[char[]] testarray = [ // yah - native array's in prop. def's
"one": "1",
"two": "2"
]; // oops - this doesnt work (although it may do in the future)
// thanks to Jarrett Billingsley for spotting this..
char[][] testarray = [ // well, semi-yah limited support
1: "atest", // for assoc. array initalizers..
5: "another test",
];
this() // yeap that's the constructor..
{
super("DUI Hello World"); // like parent::_construct()
this.setBorderWidth(10); // you dont need this. , but
// I think it add's clarity.
this.add(new Label("Hello World" ~ testarray["one"]));
// string concat with the ~
// operator.
this.show();
}
}
void main(char[][] args)
{
DUI dui = DUI.dui(args); // pass parameters to Gtk+
new HelloWorld();
dui.go(); // start the main event loop
}