procedure p1;
begin
...
end;How to get all caller adresses of p1 in a program before p1 is executed?
For example p1 is called from 20 different places in a program. Then I need the 20 caller adresses.

Mailing lists / fpc-pascal / 2012-08
32 messages · 8 people · –
Reply by email Subscribe to this list Your subscription
Read-only archive. Use j and k to move between messages.
procedure p1;
begin
...
end;How to get all caller adresses of p1 in a program before p1 is executed?
For example p1 is called from 20 different places in a program. Then I need the 20 caller adresses.
if by address you mean line number, then use the Find In Files dialog. Close all files in the Source Editor except the one containing p1 procedures.
In the "Text to Find" field type p1.
In the "Where" radiogroup select "Search all open files". Should give you a list of every occurrence of p1.
Howard
procedure p1; begin ... end; How to get all caller adresses of p1 in a program before p1…
At run time, or design time?
at design time, there is find in files, codetools "find references", or add "deprecated" and let compile and see the warnings.
At runtime, you can get the address, and if you have debug info, also the unit and line.
Run in debugger and use the stack window.
Or use (in your source code , needs console , or logfile) dumpstack();
At runtime.
I ment the (memory) caller adresses.
If p1 is executed I can get the caller adress with the rtl function:
get_caller_addr( get_frame );But I want to scan the whole program before all p1's are called by the program to get all caller adresses of p1.
May be I write an own scan program to find all calling places which calls p1.
For that I need the memory adress where the program starts. And the length.
At runtime, you can get the address, and if you have debug info, also the unit and line. Run in debugger and use the stack window. Or use (in your source code , needs console , or logfile) dumpstack();
I would like to do it without debug info.
You know that scanning the binary code for calls is platform dependant? So you'd need to write that code for every CPU you want to support. Also this is much harder to do for CISC CPUs like x86 than for RISC CPUs (ARM, MIPS, etc), because the former have variable length opcodes. So you'd basically need to write a full blown dissembler...
Maybe it would be more interesting to know why you need this beforehand?
Regards,
Sven
Sven Barth wroteYou know that scanning the binary code for calls is platform dependant?
Yes.
[calling opcode] [calleradress]
calling opcode can differ and the byteorder of the adress can differ.
So you'd need to write that code for every CPU you want to support. Also this is much harder to do for CISC CPUs like x86 than for RISC CPUs (ARM, MIPS, etc), because the former have variable length opcodes. So you'd basically need to write a full blown dissembler...
It seems hard. By now I support only 80x86 CPU's.
Maybe it would be more interesting to know why you need this beforehand?
So you mean you can convince me to find another solution?
I need this for internationalisation.
p1( 'german snippet' );
is put in a table (caller adress and text) if calling the first time and translated in other languages.
If I have a list of all p1's I know which language snippet was already called and which snippet was not yet translated (called).
If there is a new snippet in the program and called at least one time it is added to the "must be translated list".
Another method would be if it would be possible to inc a constant at compile time!
const counter = 0;
p1( [counter++](at compiletime!) , 'german snippet');But this is an insurmountable obstacle for the compilerprogrammers I think.
The problem here is the following:
Let's suppose the opcode for calling a function on x86 CPUs is 0xCA11. Now you scan through the code looking for 0xCA11 followed by 4 bit. The problem now is that without knowing the context of a found location 0xCA11 you don't know whether it is really a call opcode or some immediate data that was passed to some previous opcode. This is also an obstacle experienced by VM developers for x86 instructions (or CISC instructions in general). For RISC instruction sets this is less complex, but the problem exists there as well.
Out of curiosity: why don't you use resourcestrings?
And why do you need the count of calls (or usages)?
Regards,
Sven
At runtime. I ment the (memory) caller adresses. If p1 is executed I can get the caller…
You can probably reuse sone code from the system unit.
below is a copy of dump_stack from fpc. It gets all the addresses
{$ifdef FPC_HAS_FEATURE_CONSOLEIO}
Procedure dump_stack(var f : text;bp : Pointer);
var
i : Longint;
prevbp : Pointer;
is_dev : boolean;
caller_frame,
caller_addr : Pointer;
Begin
{$ifdef FPC_HAS_FEATURE_EXCEPTIONS}
try
{$endif FPC_HAS_FEATURE_EXCEPTIONS}
prevbp:=bp-1;
i:=0;
is_dev:=do_isdevice(textrec(f).Handle);
while bp > prevbp Do
Begin
caller_addr := get_caller_addr(bp);
caller_frame := get_caller_frame(bp);
if (caller_addr=nil) then
break;
Writeln(f,BackTraceStrFunc(caller_addr));
if (caller_frame=nil) then
break;
Inc(i);
If ((i>max_frame_dump) and is_dev) or (i>256) Then
break;
prevbp:=bp;
bp:=caller_frame;
End;
{$ifdef FPC_HAS_FEATURE_EXCEPTIONS}
except
{ prevent endless dump if an exception occured }
end;
{$endif FPC_HAS_FEATURE_EXCEPTIONS}
End;The problem here is the following: Let's suppose the opcode for calling a function on x86…
Sven Barth wroteThe problem here is the following: Let's suppose the opcode for calling a function on x86 CPUs is 0xCA11. Now you scan through the code looking for 0xCA11 followed by 4 bit.
Byte :-)
If I have the opcode 0xCA11 and the adress of p1 (suppose) 0x6EF7CAB0 then I have 6 bytes (0xCA116EF7CAB0). That reduces drastically the possibility of some immediate random data. I have to search byte by byte then for the 6 sequential bytes (48 Bits). :-)
...
Out of curiosity: why don't you use resourcestrings?
It seems that is has not the flexibility and simplicity (in its entirety) that I want. Also it depends on a unit as I see. With resourestring a have to give every snippet a name. With my solution it is not necessary. The names are automatically registered in a table (if called once).
And why do you need the count of calls (or usages)?
I need the count of p1's to see if every snipped was already called by the program. This is important when adding a new language or if the original text snippets change.
Thers is a table with all snippets and a flag (*) if a snippet was already called by the program.
Text1*
Text2*
Text3*
Text4
Text5*
Text6
Text7*
Text8
Text9*
Text10*
4,6 and 8 was not called yet by the program.
But this I can only implement if it is possible to get the whole amount (memoryadresses and/or counts) of p1 in the whole program.
You can probably reuse sone code from the system unit. below is a copy of dump_stack from…
I do not understand this ...
What is the content of the stack?
Which file 'f'?
Is it read from or write to file 'f'?
Ok write to file 'f'. :-)
But I still do not understand.
Byte :-) If I have the opcode 0xCA11 and the adress of p1 (suppose) 0x6EF7CAB0 then I…
It doesn't work like that. Regular calls use relative offsets on most (if not all) architectures we support. And in some cases we generate position-independent code, so then you'll have look at GOT entries to figure out the address. Then there are of course calls via procedure variables. And there's probably a ton more special cases I'm not thinking of right now.
> Out of curiosity: why don't you use resourcestrings? It seems that is has not the flexibility and simplicity (in its entirety) that I want.
I would not call your method "simple" and would also strongly recommend to use resourcestrings instead. Their purpose is exactly to make it easy to translate the strings in a program.
Jonas
Would it then be possible to implement a counter (const) which is increased at compile time?
p1( increasedcounteratcompiletime , 'Textsnippet' ) ?
I guess it is not possible.
It may is in the beginning more difficult to implement, but if it runs once I would say this can not get much more simpler.
You only have to put p1( ) around your text snippet. That is it! The function returns the right language.
and would also strongly recommend to use resourcestrings instead. Their purpose is exactly to make it easy to translate the strings in a program.
That means more work to give every text snippet explicitly a name which is not necessary with my solution. And that means also less flexibility.
The resourcestring solution does not record the date and time when a text was changed and so on...
Somehow this sounds like the GNU GetText function _() works. With the exception that the text which has to be translated is simply searched by looking through the source code for _("some text")...
Regards,
Sven
I do not understand this ... What is the content of the stack? Which file 'f'? Is it read…
f is just the STDOUT or logfile where the list of addresses is written to. You would likely use an array instead...
But let me say: I am with everyone else. Using stack/caller info is the wrong(est) way.
And if you need to ask "What is the content of the stack?" Then you should not use it.
All this functions are very low level. Usinc this kind of data implies having a very good understanding of the way the stack is organized.
-----------
Why do you not keep al ist of all the snippets you have seen (keep a copy of the text (strings are copy on write, so you do not need a real copy, just a 2nd string of the same text).
Somehow this sounds like the GNU GetText function _() works. With the exception that the…
In our previous episode, Sven Barth said:
Note that one of the problems of this is that it makes your text also the key that identifies an unique piece of text.
While I use (dx)gettext myself, I still think that is one of the disadvantages.
P.s. the _() is not necessary with D2009+ anymore
Would it then be possible to implement a counter (const) which is increased at compile…
How about using memory for string constant to store pointer to localized version - something like example below? Note: target platform needs to support writable string constants, and there should be enought ~ characters at the beginning of the string to store value of pointer (4x~ for 32-bit pointers, 8x~ for 64bit pointers). If you can meet these two conditions, you don't need to know internals of compiler or any implementation detail.
program test_str_36;
uses
sysutils;
function s(str: pchar): pchar;
var
str2: pchar;
begin
if str[0] = '~' then
begin
// string is not localized
str2 := strnew('numero'); // localized version
ppchar(str)^ := str2;
end;
result := ppchar(str)^;
end;
var
i: integer;
begin
for i := 1 to 10 do
begin
writeln(s('~~~~~~~~number'), ' ', i);
end;
end._______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal
f is just the STDOUT or logfile where the list of addresses is written to. You would…
Martin wroteBut let me say: I am with everyone else. Using stack/caller info is the wrong(est) way.
I fully agree.
And if you need to ask "What is the content of the stack?" Then you should not use it. All this functions are very low level. Usinc this kind of data implies having a very good understanding of the way the stack is organized.
Why do you not keep al ist of all the snippets you have seen (keep a copy of the text (strings are copy on write, so you do not need a real copy, just a 2nd string of the same text).
Can you explain it more?
I want not search through the sourcecode, because it makes it less easy.
All I need is all caller adresses of p1 in the program. Or an incremented seems impossible by now.
If p1 is called then I can see which snippet was not yet called. If the compilerincremented counter at the end is 500, then I need 500 snippet entries and I can see which entry already was called by the program during execution.
On 06/08/2012 21:39, Rainer Stratmann wrote
Can you explain it more? I want not search through the sourcecode, because it makes it less easy.
How does an address like $040012a help you find the source?
I am still trying to understand what exactly you try to archive.
What I understand sofar:
- your program has a fixed amount of text snippets in a given language QUESTION: are those snippets unique? Or can there be 2 individual snippets, that have the same text, but must be treated as different?
- you want to implement a method that translates them
- you want to ensure this method was called exactly (or is it at least?) once, for each snippet.
For some reason that I do not understand yet, you need a unique identifier for each snippet.
Well if the text of the snippets is unique, then you can use the text itself.
So instead of using $040012a as token, you can use 'hello world'
----------
That is, I still do not see, why you go this must have a list of all translations somewhere, and somehow you translate each snippet. For updating translations, you can
1) add each snippet that has no translation to a list
2) mark each translation, once it was used, and when the app finishes list all translations that where not used.
---
Or explain again what you try to do?
On Mon, Aug 6, 2012 at 9:48 PM, Rainer Stratmann How about using memory for string…
const prestr = '~~~~~~~~';That seems somehow interesting.
But you have to put it everywhere in front.
May be a macro can do it so that you have only s() left. And may be (but not very likely when reading the statement of Jonas) you can search the whole program for '~~~~~~~~' to get the caller adresses of s().
On 06/08/2012 21:39, Rainer Stratmann wrote How does an address like $040012a help you…
Martin wroteI am still trying to understand what exactly you try to archive.
Ok, I read one of the other posts: Do you need to ensure to handle each snippet only once?
Are *ALL* snippets constants?
either
const t1 = 'abc';or
foo('text')
and NEVER result of
- a function snip := copy('aaa',1,2) or snip := foo();
- any operation, such as concatenation: snip := s1+s2;If the are: use the address of the first char in the snippet
On 06/08/2012 21:39, Rainer Stratmann wrote How does an address like $040012a help you…
If I have a list with all caller adresses then I know which one was already called and I can faster search this if only handle the adress (speed reason).
I am sure you mean achieve :-)
What I understand sofar: - your program has a fixed amount of text snippets in a given language
yes
QUESTION: are those snippets unique? Or can there be 2 individual snippets, that have the same text, but must be treated as different?
both, I will able to handle it p1, p_unique, and so on.
- you want to implement a method that translates them
yes
- you want to ensure this method was called exactly (or is it at least?) once, for each snippet.
No.
I want to register a call.
I (fast) search through the adress-table every time. If the adress is in the table then I have already the translated pchar at array nr x. If not I have to translate the string and add the caller adress to the table and the pchar to the translated string.
Further on I can do with the table and string snippets what I want. If I have an Idea in the future I can implement. For example adding date and time of changes and so on.
see above.
I want the text to stay in the sourcecode and not want to have some kind of excel-list.
For updating translations, you can 1) add each snippet that has no translation to a list 2) mark each translation, once it was used, and when the app finishes list all translations that where not used.
For that I have to call every s() in the program, because I do not have a fixed list.
To know if every s() in the program was called it would be good to know every presence of s().
I tried also a kind of excel list with unique identifyer for each snippet, but for me it seems not flexible enough and much work instead of putting s() around every snippet.
--- Or explain again what you try to do?
The translation should be done by a web based interface from the inhabitant of every country (simplicity, less work for me). So I need a registration and I need to be flexible. Snippets can change, and so on. It would be good to save the older snippets if one has changed... All this can be implemented. Date & Timestamp...
Ok, I read one of the other posts: Do you need to ensure to handle each snippet only once?
yes, but they are most time immediately in s( 'snippet' );either const t1 = 'abc'; or foo('text')
Foo I don't know by now. So guess I will not use it.
and NEVER result of - a function snip := copy('aaa',1,2) or snip := foo(); - any operation, such as concatenation: snip := s1+s2;
right.
If the are: use the address of the first char in the snippet
?
But then I do not have a list of all caller adresses of s() which I try to get.
In our previous episode, Sven Barth said: Note that one of the problems of this is that…
Which reminds me: Delphi uses a different style of resource string system. In FPC you can set up the resourcestrings table based while in Delphi a "LoadResString" function is used each time a resourcestring is accessed. You can override the default functionality by setting a corresponding procedure variable. See also here
http://docwiki.embarcadero.com/Libraries/en/System.LoadResString
It wouldn't solve the problem of "declaring a resourcestring" though and also the function doesn't get the "resource string identifier" as the table based function in FPC currently gets... so in that regard the system seems more limited (while it has some positive aspects as well).
Regards,
Sven
yes, but they are most time immediately in s( 'snippet' ); Foo I don't know by now. So…
I still do not understand what is so special about the caller address? Furthermore, you said yourself, you do not need it. You can also live withe a "number that the compiler generates at compilation time".
so if you had
p(next_compile_time_number, 'text');then all p gets is 109, 'text'
if that 109 does help, why not the address of the 1st char?
---
I know there is still something about your idea that I havent got.... which makes this a bit hard.
Lets take a step back:
Why do you not just store all snippets in a stringlist, if p saw them? (speed should not be a reason, that can be dealt with)
You can always extend the list to store additional info per field.
-----------
ps
foo = placeholder
I fully agree. Can you explain it more? I want not search through the sourcecode, because…
Rainer Stratmann wroteAll I need is all caller adresses of p1 in the program.
You might be able to do that sort of thing by running the program with a profiler and analyzing all captured stacks. But it would be a vast amount of effort, and unless you could guarantee 100% coverage (i.e. feeding the program all possible input states etc.) you'd probably miss combinations.
You're left with the options of learning how to use resourcestrings effectively, or using a language such as Smalltalk where the senders of a message are known in advance.
I still do not understand what is so special about the caller address? Furthermore, you…
Martin wroteI still do not understand what is so special about the caller address? Furthermore, you said yourself, you do not need it. You can also live withe a "number that the compiler generates at compilation time".
With all caller adresses OR all numbers (see down) I have the whole amount of snippets that I want to have.
The caller adress is a unique identifier.
A handle.
so if you had p(next_compile_time_number, 'text');
I do not write something about 'next_compile_time_number'. My words were 'incremented counter at compiletime'.
That means the counter increases immediately after every occurence in the sourcecode.
I want to have all caller adresses of s() before s() is called.
Lets take a step back: Why do you not just store all snippets in a stringlist, if p saw them?
I do it.
But I need the information which snippet was not called yet. That is all I want.
(speed should not be a reason, that can be dealt with) You can always extend the list to store additional info per field.
Yes, I know :-)
----------- ps foo = placeholder
ok thanks.
How?
I can see 2 ways you get that address
procedure p (snip:string);
begin
calleraddr := get_caller_addr(); //needs to be implemented
......
endOR
procedure p (snip:string, caller_addr:pointer);
....
and when calling
p('hello world', get_my_addr()); // needs to be implemented
*** BUT
then you run your app. You collect maybe (for example) 42 addresses with snippets
How do you know that is all of them? There may be places that call p() but that where not executed. Then you do not have that address, so you do not know it is missing
The caller adress is a unique identifier. A handle.
**IF** each snippet is unique (that is if each text exists only once) Then the text itself can be used as a unique ID
yes it is longer, and compares slower, but a hash table can solve that
That is what I meant: Take 'next_compile_time_number' as a macro or preprocesser driective
Now in that case, if you know the highest number (but you do not know it), you would be able to check completness
what do you mean before s is called?
You want the compiler (at compile time) to build a table (array) of all places that call p, so you can check if they called? That is something you never said (or I missed it)
See above. I have yet to know, how that works with the caller address
Martin wrote> With all caller adresses OR all numbers (see down) I have the whole > amount of snippets that I want to have. How?
With the compiler keyword 'calleradresstable';
function s( str : pchar ) : pchar; calleradresstable;Then the compiler makes a table of all calleradresses and also the amount of s() in the program.
With the rtl function getcalleradresstable() then I get a pointer and the amount of the array.
It exists already:
http://www.freepascal.org/docs-html/rtl/system/get_caller_addr.html
That is the point.
Then I also need all adresses from the snippets before all s() are called. Method 'caller adress' is easier and clearly.
yes it is longer, and compares slower, but a hash table can solve that
I prefer faster execution wherever it is possible with little effort.
???
Now in that case, if you know the highest number (but you do not know it), you would be able to check completness
Yes, but the number doesn't exist. I think we talk again about 2 different things here.
You want the compiler (at compile time) to build a table (array) of all places that call p, so you can check if they called? That is something you never said (or I missed it)
I say it the whole time. Beginning with the first post of this thread. Sven wanted to know why I need this, so we are discussing the snippet things now.
http://www.freepascal.org/docs-html/rtl/system/get_caller_addr.html
Interesting. I couldn't find any documentation on them, and fpc 2.6.0 does give an error.
But yes, with this added info, I can at least see what you try todo.
I knew there was something like it. But didnt have the name. So I gave a dummy name, and commented it.
But now, I have another question:
Despite calleradresstable not working for me, if it does for you, then
what is the problem?Sure get_caller_addr() returns the "return address" so it will differ. I do not know haw big the offset can unless you include a disassembler, or debug-line info, you can not get exact details. But likely you can assume a maximum offset (depending if calleradresstable is the asm or pascal statement address).
That is my wish to a compiler programmer.
Can one hear me?
Who programs the compiler?
It returns a _unique_ handle. That is what I need. Perhaps there will be some offset.
May be a compiler programmer can get the exact adresses and table for this wish.
http://www.freepascal.org/aboutus.var
> Sure get_caller_addr() returns the "return address" so it will differ. It returns a _unique_ handle. That is what I need. Perhaps there will be some offset.
You seem to throw to issues together again. the unique handle issue is solvable without this. This is only needed to get a complete list of snippets...
I got the feeling, that this feature may not happen (but I have no knowledge). I do not eve know if it can be done, since the compiler does not even know the entire list of all callers. That is the linker. and the linker is platform dependent, and at least on some platforms not part of fpc (At least as far as I know).
----------
Anyway: lets get pack to your problem.
You need a list of all snippets (or a list of IDs that can be mapped 1 to 1 to the snippets).
I haven't got the solution....
But I can suggest 2 topics for investigations
1) Resourcestrings.
You do not need to use the po attempt. BUt I would EXPECT that it is possible (and you can write your own code for that) to get a list of all resource strings in the app. So there would be the table you need.
The IDE can help you to create resourestrings from the constants in the code (though it is a bit of work)
2) The new extended RTTI? I have no idea. I do not even know how ready it is. It may not apply at all.... BUt you could ask around
3) Write your own pre-processor